124 lines
4.3 KiB
FSharp
124 lines
4.3 KiB
FSharp
#load "gateway.fsx"
|
|
|
|
open System
|
|
open System.IO
|
|
open System.Net
|
|
open System.Net.Http
|
|
open System.Text
|
|
open System.Text.Json
|
|
open System.Threading
|
|
open System.Threading.Tasks
|
|
open Gateway
|
|
|
|
let require condition message =
|
|
if not condition then
|
|
invalidOp message
|
|
|
|
type VaultHandler() =
|
|
inherit HttpMessageHandler()
|
|
|
|
let seen = ResizeArray<string * string>()
|
|
member _.Seen = seen
|
|
|
|
member private _.Respond(request: HttpRequestMessage) =
|
|
let path = request.RequestUri.AbsolutePath
|
|
|
|
let body =
|
|
if path = "/v1/auth/kubernetes/login" then
|
|
use document = JsonDocument.Parse(request.Content.ReadAsStream())
|
|
require (document.RootElement.GetProperty("role").GetString() = "bootstrap") "Vault role changed"
|
|
|
|
require
|
|
(document.RootElement.GetProperty("jwt").GetString() = "service-account-jwt")
|
|
"Vault JWT changed"
|
|
|
|
"""{"auth":{"client_token":"vault-token"}}"""
|
|
elif request.Method = HttpMethod.Get then
|
|
let token = request.Headers.GetValues("X-Vault-Token") |> Seq.exactlyOne
|
|
seen.Add(path, token)
|
|
"""{"data":{"data":{"token":"stored"}}}"""
|
|
else
|
|
let token = request.Headers.GetValues("X-Vault-Token") |> Seq.exactlyOne
|
|
seen.Add(path, token)
|
|
use document = JsonDocument.Parse(request.Content.ReadAsStream())
|
|
|
|
require
|
|
(document.RootElement.GetProperty("data").GetProperty("token").GetString() = "issued")
|
|
"Vault write did not use a KVv2 envelope"
|
|
|
|
"{}"
|
|
|
|
let response = new HttpResponseMessage(HttpStatusCode.OK)
|
|
response.Content <- new StringContent(body, Encoding.UTF8, "application/json")
|
|
|
|
response
|
|
|
|
override this.Send(request: HttpRequestMessage, _: CancellationToken) = this.Respond request
|
|
|
|
override this.SendAsync(request: HttpRequestMessage, _: CancellationToken) =
|
|
let response = this.Respond request
|
|
Task.FromResult response
|
|
|
|
type KubeHandler() =
|
|
inherit HttpMessageHandler()
|
|
|
|
member private _.Respond(request: HttpRequestMessage) =
|
|
require
|
|
(request.RequestUri.AbsolutePath = "/api/v1/namespaces/zitadel/secrets/zitadel-login-service-key")
|
|
"Kubernetes Secret path changed"
|
|
|
|
require (request.Headers.Authorization.Scheme = "Bearer") "Kubernetes bearer token was omitted"
|
|
require (request.Headers.Authorization.Parameter = "service-account-jwt") "Kubernetes bearer token changed"
|
|
let encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes "private-key")
|
|
let response = new HttpResponseMessage(HttpStatusCode.OK)
|
|
|
|
response.Content <-
|
|
new StringContent($"{{\"data\":{{\"tls.key\":\"{encoded}\"}}}}", Encoding.UTF8, "application/json")
|
|
|
|
response
|
|
|
|
override this.Send(request: HttpRequestMessage, _: CancellationToken) = this.Respond request
|
|
|
|
override this.SendAsync(request: HttpRequestMessage, _: CancellationToken) = Task.FromResult(this.Respond request)
|
|
|
|
let jwtPath = Path.GetTempFileName()
|
|
|
|
try
|
|
File.WriteAllText(jwtPath, "service-account-jwt")
|
|
let handler = new VaultHandler()
|
|
|
|
let config =
|
|
{ URL = "http://vault"
|
|
Role = "bootstrap"
|
|
JwtPath = jwtPath
|
|
CaPath = "" }
|
|
|
|
use vaultClient = new HttpClient(handler, true)
|
|
let store = makeStoreWith vaultClient config
|
|
|
|
require
|
|
(store.Read "secret/data/test" = Map.ofList (List.singleton ("token", "stored")))
|
|
"Vault secret was not decoded"
|
|
|
|
store.Write "secret/data/test" (Map.ofList (List.singleton ("token", "issued")))
|
|
|
|
require
|
|
(handler.Seen |> Seq.forall (fun (_, token) -> token = "vault-token"))
|
|
"Vault operation omitted its client token"
|
|
|
|
use kubeClient = new HttpClient(new KubeHandler(), true)
|
|
|
|
let key =
|
|
readKubeKeyWith
|
|
kubeClient
|
|
{ URL = "http://kubernetes"
|
|
TokenPath = jwtPath
|
|
CaPath = ""
|
|
Namespace = "zitadel"
|
|
Secret = "zitadel-login-service-key" }
|
|
|
|
require (key = "private-key") "Kubernetes Secret key was not decoded"
|
|
|
|
printfn "bootstrap HTTP tests passed"
|
|
finally
|
|
File.Delete jwtPath
|