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
+ public static KubernetesClientConfiguration BuildConfigFromConfigFile ( string masterUrl = null , string kubeconfigPath = null )
44
+ {
45
+ return BuildConfigFromConfigFile ( new FileInfo ( kubeconfigPath ?? KubeConfigDefaultLocation ) , null , masterUrl ) ;
46
+ }
47
+
48
+ /// <summary>
49
+ ///
50
+ /// </summary>
51
+ /// <param name="kubeconfig">Fileinfo of the kubeconfig, cannot be null</param>
52
+ /// <param name="currentContext">override the context in config file, set null if do not want to override</param>
53
+ /// <param name="masterUrl">overrider kube api server endpoint, set null if do not want to override</param>
54
+ public static KubernetesClientConfiguration BuildConfigFromConfigFile ( FileInfo kubeconfig , string currentContext = null , string masterUrl = null )
55
+ {
56
+ if ( kubeconfig == null )
57
+ {
58
+ throw new NullReferenceException ( nameof ( kubeconfig ) ) ;
59
+ }
60
+
61
+ var k8SConfig = LoadKubeConfig ( kubeconfig ) ;
62
+ var k8SConfiguration = new KubernetesClientConfiguration ( ) ;
63
+ k8SConfiguration . Initialize ( k8SConfig ) ;
64
+
65
+ if ( ! string . IsNullOrWhiteSpace ( masterUrl ) )
66
+ {
67
+ k8SConfiguration . Host = masterUrl ;
68
+ }
69
+ return k8SConfiguration ;
70
+ }
71
+
72
+
73
+ /// <summary>
74
+ /// Validates and Intializes Client Configuration
75
+ /// </summary>
76
+ /// <param name="k8SConfig">Kubernetes Configuration</param>
77
+ /// <param name="currentContext">Current Context</param>
78
+ private void Initialize ( K8SConfiguration k8SConfig , string currentContext = null )
79
+ {
80
+ if ( k8SConfig . Contexts == null )
81
+ {
82
+ throw new KubeConfigException ( "No contexts found in kubeconfig" ) ;
83
+ }
84
+
85
+ if ( k8SConfig . Clusters == null )
86
+ {
87
+ throw new KubeConfigException ( $ "No clusters found in kubeconfig") ;
88
+ }
89
+
90
+ if ( k8SConfig . Users == null )
91
+ {
92
+ throw new KubeConfigException ( $ "No users found in kubeconfig") ;
93
+ }
94
+
95
+ // current context
96
+ currentContext = currentContext ?? k8SConfig . CurrentContext ;
97
+ Context activeContext =
98
+ k8SConfig . Contexts . FirstOrDefault (
99
+ c => c . Name . Equals ( currentContext , StringComparison . OrdinalIgnoreCase ) ) ;
100
+ if ( activeContext == null )
101
+ {
102
+ throw new KubeConfigException ( $ "CurrentContext: { currentContext } not found in contexts in kubeconfig") ;
103
+ }
104
+
105
+ this . CurrentContext = activeContext . Name ;
106
+
107
+ // cluster
108
+ var clusterDetails =
109
+ k8SConfig . Clusters . FirstOrDefault ( c => c . Name . Equals ( activeContext . ContextDetails . Cluster ,
110
+ StringComparison . OrdinalIgnoreCase ) ) ;
111
+ if ( clusterDetails ? . ClusterEndpoint == null )
112
+ {
113
+ throw new KubeConfigException ( $ "Cluster not found for context { activeContext } in kubeconfig") ;
114
+ }
115
+
116
+ if ( string . IsNullOrWhiteSpace ( clusterDetails . ClusterEndpoint . Server ) )
117
+ {
118
+ throw new KubeConfigException ( $ "Server not found for current-context { activeContext } in kubeconfig") ;
119
+ }
120
+
121
+ if ( ! clusterDetails . ClusterEndpoint . SkipTlsVerify &&
122
+ string . IsNullOrWhiteSpace ( clusterDetails . ClusterEndpoint . CertificateAuthorityData ) &&
123
+ string . IsNullOrWhiteSpace ( clusterDetails . ClusterEndpoint . CertificateAuthority ) )
124
+ {
125
+ throw new KubeConfigException (
126
+ $ "neither certificate-authority-data nor certificate-authority not found for current-context :{ activeContext } in kubeconfig") ;
127
+ }
128
+
129
+ this . Host = clusterDetails . ClusterEndpoint . Server ;
130
+ if ( ! string . IsNullOrEmpty ( clusterDetails . ClusterEndpoint . CertificateAuthorityData ) )
131
+ {
132
+ string data = clusterDetails . ClusterEndpoint . CertificateAuthorityData ;
133
+ this . SslCaCert = new X509Certificate2 ( System . Text . Encoding . UTF8 . GetBytes ( Utils . Base64Decode ( data ) ) ) ;
134
+ }
135
+ else if ( ! string . IsNullOrEmpty ( clusterDetails . ClusterEndpoint . CertificateAuthority ) )
136
+ {
137
+ this . SslCaCert = new X509Certificate2 ( clusterDetails . ClusterEndpoint . CertificateAuthority ) ;
138
+ }
139
+ this . SkipTlsVerify = clusterDetails . ClusterEndpoint . SkipTlsVerify ;
140
+
141
+ // user
142
+ this . SetUserDetails ( k8SConfig , activeContext ) ;
143
+ }
144
+
145
+ private void SetUserDetails ( K8SConfiguration k8SConfig , Context activeContext )
146
+ {
147
+ var userDetails = k8SConfig . Users . FirstOrDefault ( c => c . Name . Equals ( activeContext . ContextDetails . User ,
148
+ StringComparison . OrdinalIgnoreCase ) ) ;
149
+
150
+ if ( userDetails == null )
151
+ {
152
+ throw new KubeConfigException ( "User not found for context {activeContext.Name} in kubeconfig" ) ;
153
+ }
154
+
155
+ if ( userDetails . UserCredentials == null )
156
+ {
157
+ throw new KubeConfigException ( $ "User credentials not found for user: { userDetails . Name } in kubeconfig") ;
158
+ }
159
+
160
+ var userCredentialsFound = false ;
161
+
162
+ // Basic and bearer tokens are mutually exclusive
163
+ if ( ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . Token ) )
164
+ {
165
+ this . AccessToken = userDetails . UserCredentials . Token ;
166
+ userCredentialsFound = true ;
167
+ }
168
+ else if ( ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . UserName ) &&
169
+ ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . Password ) )
170
+ {
171
+ this . Username = userDetails . UserCredentials . UserName ;
172
+ this . Password = userDetails . UserCredentials . Password ;
173
+ userCredentialsFound = true ;
174
+ }
175
+
176
+ // Token and cert based auth can co-exist
177
+ if ( ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . ClientCertificateData ) &&
178
+ ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . ClientKeyData ) )
179
+ {
180
+ this . ClientCertificateData = userDetails . UserCredentials . ClientCertificateData ;
181
+ this . ClientCertificateKey = userDetails . UserCredentials . ClientKeyData ;
182
+ userCredentialsFound = true ;
183
+ }
184
+
185
+ if ( ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . ClientCertificate ) &&
186
+ ! string . IsNullOrWhiteSpace ( userDetails . UserCredentials . ClientKey ) )
187
+ {
188
+ this . ClientCertificate = userDetails . UserCredentials . ClientCertificate ;
189
+ this . ClientKey = userDetails . UserCredentials . ClientKey ;
190
+ userCredentialsFound = true ;
191
+ }
192
+
193
+ if ( ! userCredentialsFound )
194
+ {
195
+ throw new KubeConfigException (
196
+ $ "User: { userDetails . Name } does not have appropriate auth credentials in kubeconfig") ;
197
+ }
198
+ }
199
+
200
+ /// <summary>
201
+ /// Loads Kube Config
202
+ /// </summary>
203
+ /// <param name="config">Kube config file contents</param>
204
+ /// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
205
+ private static K8SConfiguration LoadKubeConfig ( FileInfo kubeconfig )
206
+ {
207
+ if ( ! kubeconfig . Exists )
208
+ {
209
+ throw new KubeConfigException ( $ "kubeconfig file not found at { kubeconfig . FullName } ") ;
210
+ }
211
+ var kubeconfigContent = File . ReadAllText ( kubeconfig . FullName ) ;
212
+
213
+ var deserializeBuilder = new DeserializerBuilder ( ) ;
214
+ var deserializer = deserializeBuilder . Build ( ) ;
215
+ return deserializer . Deserialize < K8SConfiguration > ( kubeconfigContent ) ;
216
+ }
217
+ }
218
+ }
0 commit comments