github.com/argoproj/argo-cd/v3@v3.2.1/cmd/argocd/commands/repocreds.go (about) 1 package commands 2 3 import ( 4 stderrors "errors" 5 "fmt" 6 "os" 7 "text/tabwriter" 8 9 log "github.com/sirupsen/logrus" 10 "github.com/spf13/cobra" 11 12 "github.com/argoproj/argo-cd/v3/cmd/argocd/commands/headless" 13 "github.com/argoproj/argo-cd/v3/cmd/argocd/commands/utils" 14 cmdutil "github.com/argoproj/argo-cd/v3/cmd/util" 15 "github.com/argoproj/argo-cd/v3/common" 16 argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient" 17 repocredspkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/repocreds" 18 appsv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 19 "github.com/argoproj/argo-cd/v3/util/cli" 20 "github.com/argoproj/argo-cd/v3/util/errors" 21 "github.com/argoproj/argo-cd/v3/util/git" 22 utilio "github.com/argoproj/argo-cd/v3/util/io" 23 "github.com/argoproj/argo-cd/v3/util/templates" 24 ) 25 26 // NewRepoCredsCommand returns a new instance of an `argocd repocreds` command 27 func NewRepoCredsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 28 command := &cobra.Command{ 29 Use: "repocreds", 30 Short: "Manage credential templates for repositories", 31 Example: templates.Examples(` 32 # Add credentials with user/pass authentication to use for all repositories under the specified URL 33 argocd repocreds add URL --username USERNAME --password PASSWORD 34 35 # List all the configured repository credentials 36 argocd repocreds list 37 38 # Remove credentials for the repositories with specified URL 39 argocd repocreds rm URL 40 `), 41 Run: func(c *cobra.Command, args []string) { 42 c.HelpFunc()(c, args) 43 os.Exit(1) 44 }, 45 } 46 47 command.AddCommand(NewRepoCredsAddCommand(clientOpts)) 48 command.AddCommand(NewRepoCredsListCommand(clientOpts)) 49 command.AddCommand(NewRepoCredsRemoveCommand(clientOpts)) 50 return command 51 } 52 53 // NewRepoCredsAddCommand returns a new instance of an `argocd repocreds add` command 54 func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 55 var ( 56 repo appsv1.RepoCreds 57 upsert bool 58 sshPrivateKeyPath string 59 tlsClientCertPath string 60 tlsClientCertKeyPath string 61 githubAppPrivateKeyPath string 62 gcpServiceAccountKeyPath string 63 ) 64 65 // For better readability and easier formatting 66 repocredsAddExamples := ` # Add credentials with user/pass authentication to use for all repositories under https://git.example.com/repos 67 argocd repocreds add https://git.example.com/repos/ --username git --password secret 68 69 # Add credentials with bearer token authentication to use for all BitBucket Data Center repositories under https://bitbucket.example.com/scm 70 argocd repocreds add https://bitbucket.example.com/scm/ --bearer-token secret-token 71 72 # Add credentials with SSH private key authentication to use for all repositories under ssh://git@git.example.com/repos 73 argocd repocreds add ssh://git@git.example.com/repos/ --ssh-private-key-path ~/.ssh/id_rsa 74 75 # Add credentials with GitHub App authentication to use for all repositories under https://github.com/repos 76 argocd repocreds add https://github.com/repos/ --github-app-id 1 --github-app-installation-id 2 --github-app-private-key-path test.private-key.pem 77 78 # Add credentials with GitHub App authentication to use for all repositories under https://ghe.example.com/repos 79 argocd repocreds add https://ghe.example.com/repos/ --github-app-id 1 --github-app-installation-id 2 --github-app-private-key-path test.private-key.pem --github-app-enterprise-base-url https://ghe.example.com/api/v3 80 81 # Add credentials with helm oci registry so that these oci registry urls do not need to be added as repos individually. 82 argocd repocreds add localhost:5000/myrepo --enable-oci --type helm 83 84 # Add credentials with GCP credentials for all repositories under https://source.developers.google.com/p/my-google-cloud-project/r/ 85 argocd repocreds add https://source.developers.google.com/p/my-google-cloud-project/r/ --gcp-service-account-key-path service-account-key.json 86 ` 87 88 command := &cobra.Command{ 89 Use: "add REPOURL", 90 Short: "Add git repository connection parameters", 91 Example: repocredsAddExamples, 92 Run: func(c *cobra.Command, args []string) { 93 ctx := c.Context() 94 95 if len(args) != 1 { 96 c.HelpFunc()(c, args) 97 os.Exit(1) 98 } 99 100 // Repository URL 101 repo.URL = args[0] 102 103 // Specifying ssh-private-key-path is only valid for SSH repositories 104 if sshPrivateKeyPath != "" { 105 if ok, _ := git.IsSSHURL(repo.URL); ok { 106 keyData, err := os.ReadFile(sshPrivateKeyPath) 107 if err != nil { 108 log.Fatal(err) 109 } 110 repo.SSHPrivateKey = string(keyData) 111 } else { 112 errors.Fatal(errors.ErrorGeneric, "--ssh-private-key-path is only supported for SSH repositories.") 113 } 114 } 115 116 // tls-client-cert-path and tls-client-cert-key-key-path must always be 117 // specified together 118 if (tlsClientCertPath != "" && tlsClientCertKeyPath == "") || (tlsClientCertPath == "" && tlsClientCertKeyPath != "") { 119 errors.Fatal(errors.ErrorGeneric, "--tls-client-cert-path and --tls-client-cert-key-path must be specified together") 120 } 121 122 // Specifying tls-client-cert-path is only valid for HTTPS repositories 123 if tlsClientCertPath != "" { 124 if git.IsHTTPSURL(repo.URL) { 125 tlsCertData, err := os.ReadFile(tlsClientCertPath) 126 errors.CheckError(err) 127 tlsCertKey, err := os.ReadFile(tlsClientCertKeyPath) 128 errors.CheckError(err) 129 repo.TLSClientCertData = string(tlsCertData) 130 repo.TLSClientCertKey = string(tlsCertKey) 131 } else { 132 err := stderrors.New("--tls-client-cert-path is only supported for HTTPS repositories") 133 errors.CheckError(err) 134 } 135 } 136 137 // Specifying github-app-private-key-path is only valid for HTTPS repositories 138 if githubAppPrivateKeyPath != "" { 139 if git.IsHTTPSURL(repo.URL) { 140 githubAppPrivateKey, err := os.ReadFile(githubAppPrivateKeyPath) 141 errors.CheckError(err) 142 repo.GithubAppPrivateKey = string(githubAppPrivateKey) 143 } else { 144 err := stderrors.New("--github-app-private-key-path is only supported for HTTPS repositories") 145 errors.CheckError(err) 146 } 147 } 148 149 // Specifying gcpServiceAccountKeyPath is only valid for HTTPS repositories 150 if gcpServiceAccountKeyPath != "" { 151 if git.IsHTTPSURL(repo.URL) { 152 gcpServiceAccountKey, err := os.ReadFile(gcpServiceAccountKeyPath) 153 errors.CheckError(err) 154 repo.GCPServiceAccountKey = string(gcpServiceAccountKey) 155 } else { 156 err := stderrors.New("--gcp-service-account-key-path is only supported for HTTPS repositories") 157 errors.CheckError(err) 158 } 159 } 160 161 conn, repoIf := headless.NewClientOrDie(clientOpts, c).NewRepoCredsClientOrDie() 162 defer utilio.Close(conn) 163 164 // If the user set a username, but didn't supply password via --password, 165 // then we prompt for it 166 if repo.Username != "" && repo.Password == "" { 167 repo.Password = cli.PromptPassword(repo.Password) 168 } 169 170 err := cmdutil.ValidateBearerTokenAndPasswordCombo(repo.BearerToken, repo.Password) 171 errors.CheckError(err) 172 err = cmdutil.ValidateBearerTokenForGitOnly(repo.BearerToken, repo.Type) 173 errors.CheckError(err) 174 err = cmdutil.ValidateBearerTokenForHTTPSRepoOnly(repo.BearerToken, git.IsHTTPSURL(repo.URL)) 175 errors.CheckError(err) 176 177 repoCreateReq := repocredspkg.RepoCredsCreateRequest{ 178 Creds: &repo, 179 Upsert: upsert, 180 } 181 182 createdRepo, err := repoIf.CreateRepositoryCredentials(ctx, &repoCreateReq) 183 errors.CheckError(err) 184 fmt.Printf("Repository credentials for '%s' added\n", createdRepo.URL) 185 }, 186 } 187 command.Flags().StringVar(&repo.Username, "username", "", "username to the repository") 188 command.Flags().StringVar(&repo.Password, "password", "", "password to the repository") 189 command.Flags().StringVar(&repo.BearerToken, "bearer-token", "", "bearer token to the Git repository") 190 command.Flags().StringVar(&sshPrivateKeyPath, "ssh-private-key-path", "", "path to the private ssh key (e.g. ~/.ssh/id_rsa)") 191 command.Flags().StringVar(&tlsClientCertPath, "tls-client-cert-path", "", "path to the TLS client cert (must be PEM format)") 192 command.Flags().StringVar(&tlsClientCertKeyPath, "tls-client-cert-key-path", "", "path to the TLS client cert's key (must be PEM format)") 193 command.Flags().Int64Var(&repo.GithubAppId, "github-app-id", 0, "id of the GitHub Application") 194 command.Flags().Int64Var(&repo.GithubAppInstallationId, "github-app-installation-id", 0, "installation id of the GitHub Application") 195 command.Flags().StringVar(&githubAppPrivateKeyPath, "github-app-private-key-path", "", "private key of the GitHub Application") 196 command.Flags().StringVar(&repo.GitHubAppEnterpriseBaseURL, "github-app-enterprise-base-url", "", "base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3") 197 command.Flags().BoolVar(&upsert, "upsert", false, "Override an existing repository with the same name even if the spec differs") 198 command.Flags().BoolVar(&repo.EnableOCI, "enable-oci", false, "Specifies whether helm-oci support should be enabled for this repo") 199 command.Flags().StringVar(&repo.Type, "type", common.DefaultRepoType, "type of the repository, \"git\" or \"helm\"") 200 command.Flags().StringVar(&gcpServiceAccountKeyPath, "gcp-service-account-key-path", "", "service account key for the Google Cloud Platform") 201 command.Flags().BoolVar(&repo.ForceHttpBasicAuth, "force-http-basic-auth", false, "whether to force basic auth when connecting via HTTP") 202 command.Flags().BoolVar(&repo.UseAzureWorkloadIdentity, "use-azure-workload-identity", false, "whether to use azure workload identity for authentication") 203 command.Flags().StringVar(&repo.Proxy, "proxy-url", "", "If provided, this URL will be used to connect via proxy") 204 return command 205 } 206 207 // NewRepoCredsRemoveCommand returns a new instance of an `argocd repocreds rm` command 208 func NewRepoCredsRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 209 command := &cobra.Command{ 210 Use: "rm CREDSURL", 211 Short: "Remove repository credentials", 212 Example: templates.Examples(` 213 # Remove credentials for the repositories with URL https://git.example.com/repos 214 argocd repocreds rm https://git.example.com/repos/ 215 `), 216 Run: func(c *cobra.Command, args []string) { 217 ctx := c.Context() 218 219 if len(args) == 0 { 220 c.HelpFunc()(c, args) 221 os.Exit(1) 222 } 223 conn, repoIf := headless.NewClientOrDie(clientOpts, c).NewRepoCredsClientOrDie() 224 defer utilio.Close(conn) 225 226 promptUtil := utils.NewPrompt(clientOpts.PromptsEnabled) 227 228 for _, repoURL := range args { 229 canDelete := promptUtil.Confirm(fmt.Sprintf("Are you sure you want to remove '%s'? [y/n] ", repoURL)) 230 if canDelete { 231 _, err := repoIf.DeleteRepositoryCredentials(ctx, &repocredspkg.RepoCredsDeleteRequest{Url: repoURL}) 232 errors.CheckError(err) 233 fmt.Printf("Repository credentials for '%s' removed\n", repoURL) 234 } else { 235 fmt.Printf("The command to remove '%s' was cancelled.\n", repoURL) 236 } 237 } 238 }, 239 } 240 return command 241 } 242 243 // Print the repository credentials as table 244 func printRepoCredsTable(repos []appsv1.RepoCreds) { 245 w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) 246 fmt.Fprintf(w, "URL PATTERN\tUSERNAME\tSSH_CREDS\tTLS_CREDS\n") 247 for _, r := range repos { 248 if r.Username == "" { 249 r.Username = "-" 250 } 251 fmt.Fprintf(w, "%s\t%s\t%v\t%v\n", r.URL, r.Username, r.SSHPrivateKey != "", r.TLSClientCertData != "") 252 } 253 _ = w.Flush() 254 } 255 256 // Print list of repo urls or url patterns for repository credentials 257 func printRepoCredsUrls(repos []appsv1.RepoCreds) { 258 for _, r := range repos { 259 fmt.Println(r.URL) 260 } 261 } 262 263 // NewRepoCredsListCommand returns a new instance of an `argocd repo list` command 264 func NewRepoCredsListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { 265 var output string 266 command := &cobra.Command{ 267 Use: "list", 268 Short: "List configured repository credentials", 269 Example: templates.Examples(` 270 # List all repo urls 271 argocd repocreds list 272 273 # List all repo urls in json format 274 argocd repocreds list -o json 275 276 # List all repo urls in yaml format 277 argocd repocreds list -o yaml 278 279 # List all repo urls in url format 280 argocd repocreds list -o url 281 `), 282 Run: func(c *cobra.Command, _ []string) { 283 ctx := c.Context() 284 285 conn, repoIf := headless.NewClientOrDie(clientOpts, c).NewRepoCredsClientOrDie() 286 defer utilio.Close(conn) 287 repos, err := repoIf.ListRepositoryCredentials(ctx, &repocredspkg.RepoCredsQuery{}) 288 errors.CheckError(err) 289 switch output { 290 case "yaml", "json": 291 err := PrintResourceList(repos.Items, output, false) 292 errors.CheckError(err) 293 case "url": 294 printRepoCredsUrls(repos.Items) 295 case "wide", "": 296 printRepoCredsTable(repos.Items) 297 default: 298 errors.CheckError(fmt.Errorf("unknown output format: %s", output)) 299 } 300 }, 301 } 302 command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|url") 303 return command 304 }