A Kubernetes operator that bridges Hardware Security Module (HSM) data storage with Kubernetes Secrets, providing true secret portability th
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add new test cmd function

+166 -1
+7 -1
Dockerfile
··· 39 39 # Strip debug symbols to reduce binary size (-s -w) 40 40 RUN CGO_ENABLED=1 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -ldflags="-s -w" -o hsm-operator cmd/hsm-operator/main.go 41 41 42 + # Build test utility for manual testing/debugging 43 + RUN CGO_ENABLED=1 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -ldflags="-s -w" -o test cmd/test/main.go 44 + 42 45 # Collect all runtime dependencies using iterative discovery: 43 46 # 1. Start with ldd on binaries → get compile-time linked libraries 44 47 # 2. Recursively: ldd on discovered libraries → get their dependencies ··· 46 49 # 4. Repeat step 2-3 on newly discovered libraries until no new deps found 47 50 RUN echo "Discovering runtime dependencies (iterative)..." && \ 48 51 # Define binaries to scan (includes CCID driver to catch libusb dependency) 49 - SCAN_BINARIES="/workspace/hsm-operator /usr/sbin/pcscd /usr/bin/pkcs11-tool /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Linux/libccid.so" && \ 52 + SCAN_BINARIES="/workspace/hsm-operator /workspace/test /usr/sbin/pcscd /usr/bin/pkcs11-tool /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Linux/libccid.so" && \ 50 53 mkdir -p /runtime-deps && \ 51 54 touch /tmp/deps_all.txt /tmp/deps_previous.txt /tmp/deps_new.txt && \ 52 55 # Start with our binaries ··· 141 144 142 145 # Copy application binary (manages pcscd lifecycle internally - no shell needed) 143 146 COPY --from=builder /workspace/hsm-operator /hsm-operator 147 + 148 + # Copy test utility for debugging and manual testing 149 + COPY --from=builder /workspace/test /test 144 150 145 151 # Default to nonroot user for security (manager/discovery modes don't need root) 146 152 # Agent mode overrides to root via Kubernetes securityContext for USB device access
+159
cmd/test/main.go
··· 1 + package main 2 + 3 + import ( 4 + "context" 5 + "fmt" 6 + "log" 7 + "os" 8 + 9 + "github.com/evanjarrett/hsm-secrets-operator/internal/hsm" 10 + ) 11 + 12 + func main() { 13 + if len(os.Args) < 3 { 14 + printUsage() 15 + os.Exit(1) 16 + } 17 + 18 + operation := os.Args[1] 19 + pin := os.Args[2] 20 + 21 + // Get library path from environment or use default 22 + libraryPath := os.Getenv("PKCS11_LIBRARY") 23 + if libraryPath == "" { 24 + // Try common locations 25 + if _, err := os.Stat("/usr/lib64/pkcs11/opensc-pkcs11.so"); err == nil { 26 + libraryPath = "/usr/lib64/pkcs11/opensc-pkcs11.so" // Fedora/RHEL 27 + } else if _, err := os.Stat("/usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so"); err == nil { 28 + libraryPath = "/usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so" // Debian/Ubuntu 29 + } else { 30 + log.Fatal("Could not find PKCS#11 library. Set PKCS11_LIBRARY environment variable.") 31 + } 32 + } 33 + 34 + // Create HSM client 35 + client := hsm.NewPKCS11Client() 36 + 37 + // Configure with static PIN provider 38 + config := hsm.Config{ 39 + PKCS11LibraryPath: libraryPath, 40 + SlotID: 0, 41 + UseSlotID: true, 42 + PINProvider: hsm.NewStaticPINProvider(pin), 43 + } 44 + 45 + ctx := context.Background() 46 + if err := client.Initialize(ctx, config); err != nil { 47 + log.Fatalf("Failed to initialize: %v", err) 48 + } 49 + defer client.Close() 50 + 51 + // Execute operation 52 + switch operation { 53 + case "create", "write": 54 + if len(os.Args) < 4 { 55 + fmt.Println("Usage: test create <pin> <secret-name> [key1=value1] [key2=value2] ...") 56 + os.Exit(1) 57 + } 58 + secretName := os.Args[3] 59 + data := make(map[string][]byte) 60 + 61 + // Parse key=value pairs 62 + if len(os.Args) > 4 { 63 + for _, arg := range os.Args[4:] { 64 + key, value := "", "" 65 + for i, c := range arg { 66 + if c == '=' { 67 + key = arg[:i] 68 + value = arg[i+1:] 69 + break 70 + } 71 + } 72 + if key == "" { 73 + fmt.Printf("Invalid argument: %s (expected key=value)\n", arg) 74 + os.Exit(1) 75 + } 76 + data[key] = []byte(value) 77 + } 78 + } else { 79 + // Default empty secret 80 + data["data"] = []byte("") 81 + } 82 + 83 + fmt.Printf("Creating secret '%s' with %d keys...\n", secretName, len(data)) 84 + // Convert to SecretData type and write with nil metadata 85 + secretData := hsm.SecretData(data) 86 + if err := client.WriteSecret(ctx, secretName, secretData, nil); err != nil { 87 + log.Fatalf("Failed to write secret: %v", err) 88 + } 89 + fmt.Println("✅ Successfully created secret!") 90 + 91 + case "read", "get": 92 + if len(os.Args) < 4 { 93 + fmt.Println("Usage: test read <pin> <secret-name>") 94 + os.Exit(1) 95 + } 96 + secretName := os.Args[3] 97 + 98 + fmt.Printf("Reading secret '%s'...\n", secretName) 99 + data, err := client.ReadSecret(ctx, secretName) 100 + if err != nil { 101 + log.Fatalf("Failed to read secret: %v", err) 102 + } 103 + 104 + fmt.Printf("✅ Secret '%s' has %d keys:\n", secretName, len(data)) 105 + for key, value := range data { 106 + fmt.Printf(" %s: %s\n", key, string(value)) 107 + } 108 + 109 + case "delete", "remove": 110 + if len(os.Args) < 4 { 111 + fmt.Println("Usage: test delete <pin> <secret-name>") 112 + os.Exit(1) 113 + } 114 + secretName := os.Args[3] 115 + 116 + fmt.Printf("Deleting secret '%s'...\n", secretName) 117 + if err := client.DeleteSecret(ctx, secretName); err != nil { 118 + log.Fatalf("Failed to delete secret: %v", err) 119 + } 120 + fmt.Println("✅ Successfully deleted secret!") 121 + 122 + case "list": 123 + fmt.Println("Listing all secrets...") 124 + secrets, err := client.ListSecrets(ctx, "") // Empty prefix = list all 125 + if err != nil { 126 + log.Fatalf("Failed to list secrets: %v", err) 127 + } 128 + 129 + if len(secrets) == 0 { 130 + fmt.Println("No secrets found") 131 + } else { 132 + fmt.Printf("Found %d secrets:\n", len(secrets)) 133 + for _, secret := range secrets { 134 + fmt.Printf(" - %s\n", secret) 135 + } 136 + } 137 + 138 + default: 139 + fmt.Printf("Unknown operation: %s\n", operation) 140 + printUsage() 141 + os.Exit(1) 142 + } 143 + } 144 + 145 + func printUsage() { 146 + fmt.Println("HSM Test Utility") 147 + fmt.Println() 148 + fmt.Println("Usage:") 149 + fmt.Println(" test create <pin> <secret-name> [key1=value1] [key2=value2] ...") 150 + fmt.Println(" test read <pin> <secret-name>") 151 + fmt.Println(" test delete <pin> <secret-name>") 152 + fmt.Println(" test list <pin>") 153 + fmt.Println() 154 + fmt.Println("Examples:") 155 + fmt.Println(" test create 648219 my-secret username=admin password=secret123") 156 + fmt.Println(" test read 648219 my-secret") 157 + fmt.Println(" test delete 648219 my-secret") 158 + fmt.Println(" test list 648219") 159 + }