diff --git a/.vscode/launch.json b/.vscode/launch.json index e1ef47e..5ceff7f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -31,6 +31,19 @@ ], "cwd": "${workspaceFolder}", "console": "integratedTerminal" + }, + { + "name": "Run and Debug CICD Tool github secret creation", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}", + "args": [ + "vault", + "create-github-secret" + ], + "cwd": "${workspaceFolder}", + "console": "integratedTerminal" } ] } \ No newline at end of file diff --git a/main.go b/main.go index e7a13d6..e68fdee 100644 --- a/main.go +++ b/main.go @@ -38,12 +38,18 @@ func main() { Run: runInitRepo, } - var createSecretCmd = &cobra.Command{ + var createDockerSecretCmd = &cobra.Command{ Use: "create-docker-secret", Short: "Creates a Docker registry secret in Vault for GHCR authentication.", Run: runCreateDockerSecret, } + var createGithubSecretCmd = &cobra.Command{ + Use: "create-github-secret", + Short: "Creates or updates a GitHub authentication secret in Vault.", + Run: runCreateGithubSecret, + } + // Define command flags for repo init initCmd.Flags().StringVar(&orgName, "org", "", "The GitHub organization (e.g., Free-Maidn)") initCmd.Flags().StringVar(&manifestsRepoName, "manifests-repo", "cicd-deployment-manifests", "The name of the manifests repository") @@ -53,7 +59,8 @@ func main() { // Add commands to their parent commands repoCmd.AddCommand(initCmd) - vaultCmd.AddCommand(createSecretCmd) + vaultCmd.AddCommand(createDockerSecretCmd) + vaultCmd.AddCommand(createGithubSecretCmd) rootCmd.AddCommand(repoCmd) rootCmd.AddCommand(vaultCmd) @@ -95,3 +102,11 @@ func runCreateDockerSecret(cmd *cobra.Command, args []string) { } fmt.Println("[SUCCESS] Docker registry secret created successfully in Vault!") } + +func runCreateGithubSecret(cmd *cobra.Command, args []string) { + if err := createAndStoreGithubAuthSecret(); err != nil { + fmt.Printf("[ERROR] Failed to create GitHub auth secret: %v\n", err) + os.Exit(1) + } + fmt.Println("[SUCCESS] GitHub auth secret created successfully in Vault!") +} diff --git a/vault.go b/vault.go index 8192976..ee76236 100644 --- a/vault.go +++ b/vault.go @@ -20,6 +20,7 @@ const ( vaultRootTokenSecretName = "vault-unseal-keys" vaultRootTokenSecretKey = "vault-root" ghcrSecretPath = "secret/ghcr-auth" + githubAuthSecretPath = "secret/github-auth" orgManagementSecretPath = "secret/org-management-pat" dockerConfigJSONKey = ".dockerconfigjson" orgManagementPATKey = "ORG_MANAGEMENT_PAT" @@ -126,21 +127,21 @@ func (vm *VaultManager) getVaultRootToken() (string, error) { return strings.TrimSpace(string(decoded)), nil } -// runVaultCommand executes a command inside the Vault pod using the `runCommand` utility. -func (vm *VaultManager) runVaultCommand(command string) error { +// runVaultCommandQuiet executes a command inside the Vault pod without printing its output. +func (vm *VaultManager) runVaultCommandQuiet(command string) error { envSetup := fmt.Sprintf("export VAULT_SKIP_VERIFY=true && export VAULT_ADDR='%s' && export VAULT_TOKEN='%s'", defaultVaultAddress, vm.rootToken) fullCmd := fmt.Sprintf("%s && %s", envSetup, command) - // Use the runCommand utility to show command output to the user. - return runCommand("kubectl", "exec", "-n", vaultNamespace, vm.podName, "--", "sh", "-c", fullCmd) + // Use the runCommandQuiet utility to suppress command stdout. + return runCommandQuiet("kubectl", "exec", "-n", vaultNamespace, vm.podName, "--", "sh", "-c", fullCmd) } -// verifyVaultToken checks if the root token is valid. +// verifyVaultToken checks if the root token is valid by running a quiet command. func (vm *VaultManager) verifyVaultToken() error { - return vm.runVaultCommand("vault token lookup") + return vm.runVaultCommandQuiet("vault token lookup") } -// StoreSecret stores a key-value secret at the specified path in Vault. +// StoreSecret stores a key-value secret at the specified path in Vault quietly. func (vm *VaultManager) StoreSecret(path string, data map[string]string) error { fmt.Printf("[INFO] Storing secret in Vault at path: %s...\n", path) @@ -152,18 +153,11 @@ func (vm *VaultManager) StoreSecret(path string, data map[string]string) error { } vaultCmd := fmt.Sprintf("vault kv put %s %s", path, strings.Join(kvPairs, " ")) - if err := vm.runVaultCommand(vaultCmd); err != nil { + if err := vm.runVaultCommandQuiet(vaultCmd); err != nil { return fmt.Errorf("failed to store secret in Vault: %w", err) } - fmt.Println("[INFO] Verifying secret storage...") - verifyCmd := fmt.Sprintf("vault kv get %s", path) - if err := vm.runVaultCommand(verifyCmd); err != nil { - fmt.Printf("[WARNING] Could not verify secret storage at '%s', but it may have been created successfully.\n", path) - } else { - fmt.Printf("[SUCCESS] Secret at '%s' stored and verified in Vault!\n", path) - } - + fmt.Printf("[SUCCESS] Secret at '%s' stored successfully in Vault!\n", path) return nil } @@ -202,6 +196,28 @@ func createAndStoreSecrets() error { return nil } +func createAndStoreGithubAuthSecret() error { + username, token, err := getUserInputForGithubAuth() + if err != nil { + return err + } + + vm, err := NewVaultManager() + if err != nil { + return fmt.Errorf("failed to initialize Vault manager: %w", err) + } + + secretData := map[string]string{ + "username": username, + "password": token, + } + if err := vm.StoreSecret(githubAuthSecretPath, secretData); err != nil { + return fmt.Errorf("failed to store github-auth secret: %w", err) + } + + return nil +} + // --- User Input and Helper Functions --- func getUserInput() (username, registryToken, orgToken string, err error) { reader := bufio.NewReader(os.Stdin) @@ -230,6 +246,28 @@ func getUserInput() (username, registryToken, orgToken string, err error) { return } +func getUserInputForGithubAuth() (username, token string, err error) { + reader := bufio.NewReader(os.Stdin) + + fmt.Print("Enter your GitHub username: ") + username, err = reader.ReadString('\n') + if err != nil { + return + } + username = strings.TrimSpace(username) + if username == "" { + err = fmt.Errorf("username cannot be empty") + return + } + + token, err = promptForToken(reader, "Enter your GitHub personal access token for repository access") + if err != nil { + return + } + + return +} + // promptForToken provides a generic way to ask for a token with validation. func promptForToken(reader *bufio.Reader, prompt string) (string, error) { fmt.Printf("%s: ", prompt)