Skip to content

Commit 88d3550

Browse files
authored
feat(authentication): support for exec kube config (#29)
1 parent 82fd83c commit 88d3550

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

Sources/SwiftkubeClient/Config/KubernetesClientConfig.swift

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,72 @@ private extension AuthInfo {
336336
} catch {
337337
logger?.warning("Error initializing authentication from client certificate: \(error)")
338338
}
339+
340+
#if os(Linux) || os(macOS)
341+
do {
342+
if let exec {
343+
let outputData = try run(command: exec.command, arguments: exec.args)
344+
345+
let decoder = JSONDecoder()
346+
decoder.dateDecodingStrategy = .iso8601
347+
let credential = try decoder.decode(ExecCredential.self, from: outputData)
348+
349+
return .bearer(token: credential.status.token)
350+
}
351+
} catch {
352+
logger?.warning("Error initializing authentication from exec \(error)")
353+
}
354+
#endif
339355
return nil
340356
}
341357
}
358+
359+
// MARK: - ExecCredential
360+
361+
// It seems that AWS doesn't implement properly the model for client.authentication.k8s.io/v1beta1
362+
// Acordingly with the doc https://kubernetes.io/docs/reference/config-api/client-authentication.v1beta1/
363+
// ExecCredential.Spec.interactive is required as long as the ones in the Status object.
364+
internal struct ExecCredential: Decodable {
365+
let apiVersion: String
366+
let kind: String
367+
let spec: Spec
368+
let status: Status
369+
}
370+
371+
internal extension ExecCredential {
372+
struct Spec: Decodable {
373+
let cluster: Cluster?
374+
let interactive: Bool?
375+
}
376+
377+
struct Status: Decodable {
378+
let expirationTimestamp: Date
379+
let token: String
380+
let clientCertificateData: String?
381+
let clientKeyData: String?
382+
}
383+
}
384+
385+
#if os(Linux) || os(macOS)
386+
internal func run(command: String, arguments: [String]? = nil) throws -> Data {
387+
func run(_ command: String, _ arguments: [String]?) throws -> Data {
388+
let task = Process()
389+
task.executableURL = URL(fileURLWithPath: command)
390+
task.arguments = arguments
391+
392+
let pipe = Pipe()
393+
task.standardOutput = pipe
394+
395+
try task.run()
396+
397+
return pipe.fileHandleForReading.availableData
398+
}
399+
400+
func resolve(command: String) throws -> String {
401+
try String(decoding:
402+
run("/usr/bin/which", ["\(command)"]), as: UTF8.self).trimmingCharacters(in: .whitespacesAndNewlines)
403+
}
404+
405+
return try run(resolve(command: command), arguments)
406+
}
407+
#endif

0 commit comments

Comments
 (0)