diff --git a/vault.go b/vault.go index cce993b..d14a2a1 100644 --- a/vault.go +++ b/vault.go @@ -30,6 +30,11 @@ type VaultSecret struct { DockerConfigJSON string `json:".dockerconfigjson"` } +// OrgManagementSecret represents the organization management PAT secret +type OrgManagementSecret struct { + OrgManagementPAT string `json:"ORG_MANAGEMENT_PAT"` +} + // createDockerRegistrySecret creates a Docker registry secret in Vault func createDockerRegistrySecret() error { // Check dependencies @@ -52,7 +57,7 @@ func createDockerRegistrySecret() error { } // Get user input - username, token, err := getUserInput() + username, token, orgToken, err := getUserInput() if err != nil { return fmt.Errorf("failed to get user input: %v", err) } @@ -63,63 +68,100 @@ func createDockerRegistrySecret() error { return fmt.Errorf("failed to create Docker config: %v", err) } - // Store in Vault - fmt.Println("[INFO] Storing secret in Vault...") + // Store Docker registry secret in Vault + fmt.Println("[INFO] Storing Docker registry secret in Vault...") if err := storeInVault(dockerConfig); err != nil { - return fmt.Errorf("failed to store secret in Vault: %v", err) + return fmt.Errorf("failed to store Docker registry secret in Vault: %v", err) + } + + // Store organization management PAT in Vault + fmt.Println("[INFO] Storing organization management PAT in Vault...") + if err := storeOrgManagementPAT(orgToken); err != nil { + return fmt.Errorf("failed to store organization management PAT in Vault: %v", err) } return nil } -// getUserInput prompts the user for their GitHub username and token -func getUserInput() (string, string, error) { +// getUserInput prompts the user for their GitHub username, registry token, and organization management token +func getUserInput() (string, string, string, error) { reader := bufio.NewReader(os.Stdin) // Get username fmt.Print("Enter your GitHub username: ") username, err := reader.ReadString('\n') if err != nil { - return "", "", err + return "", "", "", err } username = strings.TrimSpace(username) if username == "" { - return "", "", fmt.Errorf("username cannot be empty") + return "", "", "", fmt.Errorf("username cannot be empty") } - // Get token (hidden input) - fmt.Print("Enter your GitHub personal access token: ") + // Get registry token (hidden input) + fmt.Print("Enter your GitHub personal access token for container registry: ") tokenBytes, err := term.ReadPassword(int(syscall.Stdin)) if err != nil { - return "", "", err + return "", "", "", err } fmt.Println() // Print newline after hidden input token := string(tokenBytes) if token == "" { - return "", "", fmt.Errorf("token cannot be empty") + return "", "", "", fmt.Errorf("registry token cannot be empty") } - // Validate token format (GitHub tokens start with ghp_, gho_, ghu_, ghs_, or ghr_) + // Validate registry token format if !strings.HasPrefix(token, "ghp_") && !strings.HasPrefix(token, "gho_") && !strings.HasPrefix(token, "ghu_") && !strings.HasPrefix(token, "ghs_") && !strings.HasPrefix(token, "ghr_") { - fmt.Println("[WARNING] The token doesn't appear to be a GitHub personal access token (should start with ghp_, gho_, ghu_, ghs_, or ghr_)") + fmt.Println("[WARNING] The registry token doesn't appear to be a GitHub personal access token (should start with ghp_, gho_, ghu_, ghs_, or ghr_)") fmt.Print("Do you want to continue anyway? (y/N): ") confirm, err := reader.ReadString('\n') if err != nil { - return "", "", err + return "", "", "", err } confirm = strings.TrimSpace(strings.ToLower(confirm)) if confirm != "y" && confirm != "yes" { - return "", "", fmt.Errorf("operation cancelled by user") + return "", "", "", fmt.Errorf("operation cancelled by user") } } - return username, token, nil + // Get organization management token (hidden input) + fmt.Print("Enter your GitHub personal access token for organization management: ") + orgTokenBytes, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return "", "", "", err + } + fmt.Println() // Print newline after hidden input + + orgToken := string(orgTokenBytes) + if orgToken == "" { + return "", "", "", fmt.Errorf("organization management token cannot be empty") + } + + // Validate organization management token format + if !strings.HasPrefix(orgToken, "ghp_") && !strings.HasPrefix(orgToken, "gho_") && + !strings.HasPrefix(orgToken, "ghu_") && !strings.HasPrefix(orgToken, "ghs_") && + !strings.HasPrefix(orgToken, "ghr_") && !strings.HasPrefix(orgToken, "github_pat_") { + fmt.Println("[WARNING] The organization management token doesn't appear to be a GitHub personal access token (should start with ghp_, gho_, ghu_, ghs_, or ghr_)") + fmt.Print("Do you want to continue anyway? (y/N): ") + + confirm, err := reader.ReadString('\n') + if err != nil { + return "", "", "", err + } + confirm = strings.TrimSpace(strings.ToLower(confirm)) + + if confirm != "y" && confirm != "yes" { + return "", "", "", fmt.Errorf("operation cancelled by user") + } + } + + return username, token, orgToken, nil } // createDockerConfig creates a Docker config JSON structure @@ -179,23 +221,66 @@ func storeInVault(dockerConfigJSON string) error { fmt.Println("[SUCCESS] Vault token is valid") // Store the secret using kubectl exec to vault pod - fmt.Println("[INFO] Storing secret in Vault KV store...") + fmt.Println("[INFO] Storing Docker registry secret in Vault KV store...") // Use kubectl exec to run vault command inside the pod with proper env vars and token vaultCmd := fmt.Sprintf("%s && vault kv put secret/ghcr-auth .dockerconfigjson='%s'", envSetupCmd, dockerConfigJSON) if err := runCommand("kubectl", "exec", "-n", "vault", vaultPod, "--", "sh", "-c", vaultCmd); err != nil { - return fmt.Errorf("failed to store secret in Vault: %v", err) + return fmt.Errorf("failed to store Docker registry secret in Vault: %v", err) } // Verify the secret was stored - fmt.Println("[INFO] Verifying secret storage...") + fmt.Println("[INFO] Verifying Docker registry secret storage...") verifyCmd := fmt.Sprintf("%s && vault kv get secret/ghcr-auth", envSetupCmd) if err := runCommand("kubectl", "exec", "-n", "vault", vaultPod, "--", "sh", "-c", verifyCmd); err != nil { - fmt.Println("[WARNING] Could not verify secret storage, but it may have been created successfully") + fmt.Println("[WARNING] Could not verify Docker registry secret storage, but it may have been created successfully") fmt.Printf("[INFO] You can manually verify with: kubectl exec -n vault %s -- sh -c \"%s\"\n", vaultPod, verifyCmd) } else { - fmt.Println("[SUCCESS] Secret stored and verified in Vault!") + fmt.Println("[SUCCESS] Docker registry secret stored and verified in Vault!") + } + + return nil +} + +// storeOrgManagementPAT stores the organization management PAT in Vault KV v2 +func storeOrgManagementPAT(token string) error { + // Get the vault pod name + vaultPod, err := getVaultPodName() + if err != nil { + return fmt.Errorf("failed to find Vault pod: %v", err) + } + + // Get the root token + rootToken, err := getVaultRootToken() + if err != nil { + return fmt.Errorf("failed to get Vault root token: %v", err) + } + + // Set environment and authenticate + envSetupCmd := fmt.Sprintf("export VAULT_SKIP_VERIFY=true && export VAULT_ADDR='https://127.0.0.1:8200' && export VAULT_TOKEN='%s'", rootToken) + + // Store the organization management PAT + fmt.Println("[INFO] Storing organization management PAT in Vault KV store...") + + // Escape single quotes in token for shell command + escapedToken := strings.ReplaceAll(token, "'", "'\"'\"'") + + // Use kubectl exec to run vault command inside the pod + vaultCmd := fmt.Sprintf("%s && vault kv put secret/org-management-pat ORG_MANAGEMENT_PAT='%s'", envSetupCmd, escapedToken) + + if err := runCommand("kubectl", "exec", "-n", "vault", vaultPod, "--", "sh", "-c", vaultCmd); err != nil { + return fmt.Errorf("failed to store organization management PAT in Vault: %v", err) + } + + // Verify the secret was stored + fmt.Println("[INFO] Verifying organization management PAT storage...") + verifyCmd := fmt.Sprintf("%s && vault kv get secret/org-management-pat", envSetupCmd) + if err := runCommand("kubectl", "exec", "-n", "vault", vaultPod, "--", "sh", "-c", verifyCmd); err != nil { + fmt.Println("[WARNING] Could not verify organization management PAT storage, but it may have been created successfully") + fmt.Printf("[INFO] You can manually verify with: kubectl exec -n vault %s -- sh -c \"%s\"\n", vaultPod, verifyCmd) + } else { + fmt.Println("[SUCCESS] Organization management PAT stored and verified in Vault!") } return nil