Move server to a 'serve' command

This commit is contained in:
2026-03-17 12:31:51 +01:00
parent 2b2d59aa76
commit 0bc41725f8
4 changed files with 253 additions and 210 deletions

View File

@@ -3,7 +3,6 @@ package main
import (
"crypto/sha256"
"encoding/json"
"flag"
"fmt"
"io"
"net/http"
@@ -20,64 +19,6 @@ import (
"github.com/jcmturner/gokrb5/v8/spnego"
)
// runCredential implements the "ward credential" subcommand, which acts as a
// kubectl exec credential plugin. It fetches an ExecCredential JSON from the
// ward server and prints it to stdout for kubectl to consume.
//
// Authentication priority:
// 1. Kerberos SPNEGO using the active credential cache (from kinit)
// 2. Basic auth — prompts for password, or reads $WARD_PASSWORD
//
// Credentials are cached in ~/.cache/ward/ and reused until 5 minutes
// before expiry, so kubectl invocations are fast after the first call.
//
// Debug output goes to stderr (kubectl surfaces this to the terminal):
//
// WARD_DEBUG=1 kubectl get nodes
func runCredential(args []string) int {
fs := flag.NewFlagSet("credential", flag.ContinueOnError)
fs.SetOutput(os.Stderr)
server := fs.String("server", "", "ward server URL (required)")
username := fs.String("username", "", "username for Basic auth fallback (default: $USER)")
noKerberos := fs.Bool("no-kerberos", false, "skip Kerberos; always use Basic auth")
noCache := fs.Bool("no-cache", false, "bypass local cache; always fetch a fresh credential")
debug := fs.Bool("debug", os.Getenv("WARD_DEBUG") != "", "verbose debug output to stderr (also: $WARD_DEBUG=1)")
if err := fs.Parse(args); err != nil {
return 1
}
if *server == "" {
fmt.Fprintln(os.Stderr, "ward credential: --server is required")
fs.PrintDefaults()
return 1
}
logf := func(format string, a ...interface{}) {
if *debug {
fmt.Fprintf(os.Stderr, "[ward] "+format+"\n", a...)
}
}
// ── Cache ─────────────────────────────────────────────────────────────────
if !*noCache {
if ec, ok := credReadCache(*server, logf); ok {
return credPrint(ec)
}
}
// ── Fetch from ward ───────────────────────────────────────────────────
ec, err := credFetch(*server, *username, *noKerberos, logf)
if err != nil {
fmt.Fprintf(os.Stderr, "ward credential: %v\n", err)
return 1
}
if !*noCache {
credWriteCache(*server, ec, logf)
}
return credPrint(ec)
}
func credFetch(server, username string, noKerberos bool, logf func(string, ...interface{})) (*ExecCredential, error) {
url := strings.TrimRight(server, "/") + "/credential"
@@ -200,12 +141,8 @@ func credParse(body []byte) (*ExecCredential, error) {
return &ec, nil
}
func credPrint(ec *ExecCredential) int {
if err := json.NewEncoder(os.Stdout).Encode(ec); err != nil {
fmt.Fprintf(os.Stderr, "ward credential: writing output: %v\n", err)
return 1
}
return 0
func credPrint(ec *ExecCredential) error {
return json.NewEncoder(os.Stdout).Encode(ec)
}
// ── Local credential cache ─────────────────────────────────────────────────────