Zum Inhalt springen
Client-Bibliothek

Client-Bibliothek

claimward-vpn-client: die Go-Bibliothek, die sich die Apps und der Server teilen – Anmeldung, das Wire-Protokoll, der Tunnel, der privilegierte Helper und der App-Kern. Sie liefert kein Binary aus.

claimward-vpn-client v0.3.1 ist eine Go-Bibliothek. Sie liefert kein Binary aus: Die ausführbaren Programme sind die der Apps (cmd/claimward-app und cmd/claimward-helper in jedem App-Repository). Auch der Server importiert sie, für die Wire-Typen und die gRPC-Stubs.

Es gibt keinen Kommandozeilen-Client claimward. Frühere Versionen dieses Moduls hatten einen (cmd/claimward, mit login und connect); er wurde entfernt, und das reine Bibliotheksmodul ist die Grundlage der Apps.

Pakete

PaketZweck
pkg/protocolder Wire-Vertrag (/enroll, /tenants, /heartbeat, /deregister), gemeinsam mit dem Server
pkg/routespbgenerierte gRPC/Protobuf-Stubs des RouteService, gemeinsam mit dem Server
pkg/authinteraktive Anmeldung hinter einem Provider: GitHub Device Flow (Standard), OIDC Code + PKCE oder go-authn Device Flow, dessen Anbieter außerdem den Schlüssel des Geräts registriert (KeyRegistrar)
pkg/oidcder OIDC-Ablauf Authorization Code + PKCE: Discovery, Loopback-Weiterleitung
pkg/browseröffnet eine URL im Standardbrowser mit absoluten Pfaden zu den Öffnerprogrammen, damit es aus GUI-Apps heraus funktioniert
pkg/clientEnroll, Tenants, Heartbeat, Deregister gegen den Server sowie TunnelConfig, um eine EnrollResponse in eine wgtun.Config umzuwandeln
pkg/wgkeyErzeugung und Parsen von WireGuard-Schlüsseln
pkg/wgtunWireGuard-Tunnel im Userspace mit wireguard-go, dazu Adresse und Routen: ifconfig/route unter macOS, ip unter Linux, ein Wintun-Adapter über winipcfg unter Windows (mit DNS und MTU); benötigt Privilegien
pkg/routeclientbeobachtet den RouteService des Servers und meldet Aktualisierungen der Routen; TLS, außer zu Loopback
pkg/appcoredie Logik der Apps, gemeinsam für alle drei: Anmeldung, der für die Sitzung gewählte Mandant, Verbinden und Trennen über den Helper, Status für die Oberfläche
pkg/helperder privilegierte Helper, gemeinsam für die drei Apps: registriert, besitzt den Tunnel, beobachtet gepushte Routen
pkg/hproto, pkg/helperclientdas Socket-Protokoll des Helpers und der Client der App dafür
pkg/tokenstoredie Sitzung (Bearer-Token, Refresh-Token, privater Schlüssel des Geräts, gewählter Mandant) in einer JSON-Datei mit 0600

Dateien auf dem Gerät

DateiWas
<config dir>/Claimward/config.jsondie Konfiguration der App (appcore.Config), 0600, überschrieben durch die Variablen CLAIMWARD_*
<config dir>/claimward/session.jsondie Sitzung (pkg/tokenstore), 0600

<config dir> ist Go’s os.UserConfigDir(): ~/Library/Application Support unter macOS, ~/.config unter Linux, %AppData% unter Windows.

Schlüssel in config.jsonVariable
server_urlCLAIMWARD_SERVERdie Basis-URL des Servers; muss eine sein, für die der Helper konfiguriert ist
providerCLAIMWARD_AUTH_PROVIDERgithub (Standard), oidc oder go-authn
github_client_idCLAIMWARD_GITHUB_CLIENT_IDdie Client-ID der GitHub-OAuth-App
oidc_issuerCLAIMWARD_OIDC_ISSUERoidc und go-authn
oidc_client_idCLAIMWARD_OIDC_CLIENT_IDoidc und go-authn
socket_pathCLAIMWARD_HELPER_SOCKETder Socket des Helpers, falls nicht der Standard

Verwendung in eigenen Werkzeugen

ctx := context.Background()

// 1. Sign in. GitHub is the default provider (device flow).
provider, err := auth.New(auth.Config{Provider: "github", GitHubClientID: "Iv1.0123456789abcdef"})
if err != nil {
	log.Fatal(err)
}
tok, err := provider.Login(ctx, func(p auth.DevicePrompt) {
	fmt.Printf("visit %s and enter code %s\n", p.VerificationURI, p.UserCode)
})
if err != nil {
	log.Fatal(err)
}

// 2. A key pair, and with go-authn the PUBLIC key registered first: the
//    token for the server is the one RegisterKey returns.
keys, err := wgkey.Generate()
if err != nil {
	log.Fatal(err)
}
if reg, ok := provider.(auth.KeyRegistrar); ok {
	if tok, err = reg.RegisterKey(ctx, tok, keys.Public.String(), "laptop"); err != nil {
		log.Fatal(err)
	}
}

// 3. Enroll; "" lets the server use the person's only tenant.
c := client.New("https://vpn.example.com")
resp, err := c.Enroll(ctx, tok.Value, keys.Public,
	protocol.DeviceInfo{Name: "laptop", OS: "linux", Platform: "my-tool"}, "")
if err != nil {
	log.Fatal(err)
}

// 4. The tunnel (needs privileges), and optionally live routes.
cfg, err := client.TunnelConfig(resp, keys.Private)
if err != nil {
	log.Fatal(err)
}
tun, err := wgtun.Up(cfg)
if err != nil {
	log.Fatal(err)
}
defer tun.Close()
if resp.GRPCEndpoint != "" {
	go routeclient.Watch(ctx, resp.GRPCEndpoint, tok.Value, keys.Public.String(),
		func(u routeclient.Update) { _ = tun.UpdateRoutes(u.AllowedIPs) })
}

Ein langlebiger Client erneuert seine Lease mit c.Heartbeat vor resp.LeaseExpiresAt und entfernt seinen Peer mit c.Deregister, wenn er fertig ist.

Hinweise zu den Plattformen

  • DNS. Die DNS-Server des Servers werden nur unter Windows angewendet; unter macOS und Linux werden sie im Protokoll übertragen, aber pkg/wgtun wendet sie noch nicht an.
  • Gepushte Routen ersetzen die erlaubten IPs und die Routen; DNS-Änderungen in einem Push werden nicht angewendet.
  • Windows. Das Gerät ist ein Wintun-Adapter namens Claimward: wintun.dll (von https://www.wintun.net, signiert von WireGuard LLC) muss neben der ausführbaren Datei liegen, die wgtun.Up aufruft, worum sich das Packaging der Windows-App kümmert. Adresse, Routen, DNS und MTU werden über winipcfg gesetzt (die IP Helper API, reines Go, CGO_ENABLED=0).
  • Sitzungsspeicher. Eine Datei mit 0600; die Verlagerung in den Geheimnisspeicher der Plattform steht noch aus.

Erstellt am von tannevaled

Geändert am von tannevaled