Skip to content

Add repository credential management API and CLI (addresses #2136)#2207

Merged
alexec merged 55 commits intoargoproj:masterfrom
jannfis:2136-creds-management
Oct 17, 2019
Merged

Add repository credential management API and CLI (addresses #2136)#2207
alexec merged 55 commits intoargoproj:masterfrom
jannfis:2136-creds-management

Conversation

@jannfis
Copy link
Member

@jannfis jannfis commented Aug 23, 2019

This PR adds repository credential management to ArgoCD, as discussed in #2136. It changes the following:

  • Add the following CRUD operations for repository credentials in RepositoryService API Introduces new RepoCredsService API which implements the following CRUD operations for managing repository credentials:

    • ListRepositoryCredentials()
    • CreateRepositoryCredentials()
    • UpdateRepositoryCredentials()
    • DeleteRepositoryCredentials()
  • Deprecation of the following CRUD operations for repository management in RepositoryService API. The deprecated methods still available for backwards compatibility, but I think should be safe to remove with the release of v2.0:

    • List() deprecated in favour of ListRepositories()
    • Create() deprecated in favour of CreateRepository()
    • Update() deprecated in favour of UpdateRepository()
    • Delete() deprecated in favour of DeleteRepository()
  • Changes the semantics of argocd repo sub-commands by introducing the --creds switch to sub-commands list, add and rm to perform operations on repository credentials instead of repositories.

  • Introduces the repocreds sub-command to CLI, which can be used to manage repository credential templates. It mimics repo sub-command to some extent and supports the add, rm and list operations, with --upsert support.

  • Introduces --force-refresh --refresh <mode> switch to argocd repo list command and accompanyingrefresh field in RepoQuery message of RepositoryService API to force a cache refresh of the listed repository's connection status

  • Update 08/26/19: Changes behaviour of credential lookup from "first match" to "best match", i.e. given the following two cred URLs https://reposerver/reposand https://reposerver/repos/private, credential lookup for repository https://reposerver/repos/private/myprivate would return credentials configured for https://reposerver/repos/private, not https://reposerver/repos

  • Update 08/26/19 2: Adds initial functionality to the web UI for listing, adding and removing repository credential templates - all built into the 'Repositories' settings page. Also added ability to force a cache reload of repositories with a new button on top of the page. See screenshots.

  • Update 08/27/19: Added documentation for Operator Manual (declarative) and User Manual (Web UI and CLI)

  • Update 09/28/19: Introduce new repocreds sub-command to CLI and removes --creds switch (and accompanying functionality) from repo sub-command (docs still need updating).

image

image

image

CLI examples:

[eris@docker-build argo-cd]$ ./dist/argocd repocreds --list
URL_PATTERN                 USERNAME  SSH_CREDS  TLS_CREDS
https://docker-build/repos  test      false      false
[eris@docker-build argo-cd]$ ./dist/argocd repo list
REPO                                            INSECURE  LFS    USER  STATUS      MESSAGE
https://docker-build/repos/argocd-example-apps  false     false  test  Successful
[eris@docker-build argo-cd]$ ./dist/argocd repocreds rm https://docker-build/repos
[eris@docker-build argo-cd]$ ./dist/argocd repo list --refresh hard
REPO                                            INSECURE  LFS    USER  STATUS  MESSAGE
https://docker-build/repos/argocd-example-apps  false     false  -     Failed  Unable to connect to repository: authentication required

@alexec
Copy link
Contributor

alexec commented Aug 23, 2019

looking good so far - I've some polish comments - but I'll wait until this is Ready For Review

@jannfis jannfis marked this pull request as ready for review August 27, 2019 18:35
@jannfis
Copy link
Member Author

jannfis commented Aug 27, 2019

I think this PR is complete now. Sorry for it being so large again, I owe you guys a beer or two for all the review work I generate.

Copy link
Contributor

@alexec alexec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another great PR. I've just added some comments as I'm on vacation for a few days now.

@jannfis
Copy link
Member Author

jannfis commented Aug 29, 2019

Regarding the removal of insecureIgnoreHostKey from the credential templates, this was a design decision. It has a) not been well documented (no mention of this setting in the docs regarding repository credentials), and b) I see it as a potentially dangerous option, and also one that shouldn't be necessary anymore with the introduction of certificate management. The problem I see with it that it's a "fire & forget" option to open a potential huge security gap in the setup. It should be set using consent for each repository, if at all (i.e. must "hurt").

Copy link
Contributor

@alexec alexec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Helm work is now merged. You'll need to git merge master

@moensch
Copy link
Contributor

moensch commented Sep 13, 2019

@jannfis Would you consider a reduced version of this PR against the 1.2 branch to just fix the call to CreateRepository with no credentials provided?
I was going to get started on a fix for #2305 but then found your open PR which I suspect won't make it in until 2.0.

@alexec
Copy link
Contributor

alexec commented Oct 3, 2019

Don't forget to let us know when it is ready for review.

@jannfis
Copy link
Member Author

jannfis commented Oct 3, 2019

I'm still working on moving the credentials part out of RepositoryService to give the credentials a dedicated place to exist. This is more work than I expected, as I'm also giving it complete new data structures and types, so there'll be less confusion about what's actually a repository and what's a credential template.

@jannfis
Copy link
Member Author

jannfis commented Oct 4, 2019

I've introduced RepoCredsService with the latest commit, which handles CRUD operations for repository credentials. I have also changed semantics of RepositoryCredentials a little, so we now have a dedicated data structure for handling credential templates, as opposed to handle them using stub repository structures. This always introduced confusion of "what is a repository" and "what is a credential template", and which information should be where.

Final steps are now to adapt the UI to the new semantics, and also to merge the conflicts from master (I hope for the last time).

@jannfis
Copy link
Member Author

jannfis commented Oct 5, 2019

@alexec I think this is now finally ready for review. Please note that the change is now more invasive than initially was planned, but should be non breaking in terms of configuration - except when someone had InsecureIgnoreHostKey set in repository.credentials configuration (which I doubt, because it was not documented).

The UI still needs a little love, it's a little hackish implementation. I was thinking about moving the credentials part to its own settings page in the future, but for now, the current implementation in the repositories section seems good enough.

@alexec alexec self-requested a review October 7, 2019 18:31
@alexec alexec self-assigned this Oct 7, 2019
Copy link
Contributor

@alexec alexec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good me. I'd like to target if for v1.4 rather than v1.3 as we're going to branch v1.3 today (hopefully). @alexmt @jessesuen do you want to review the API changes please?

if sshPrivateKeyPath != "" {
if ok, _ := git.IsSSHURL(repo.URL); ok {
keyData, err := ioutil.ReadFile(sshPrivateKeyPath)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor - could use error.Check(..)

// Print the repository credentials as table
func printRepoCredsTable(repos []appsv1.RepoCreds) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintf(w, "URL_PATTERN\tUSERNAME\tSSH_CREDS\tTLS_CREDS\n")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor - if you want to provide parseable output, you could add a -o yaml option

// RepoCreds holds a repository credentials definition
type RepoCreds struct {
// URL is the URL that this credentials matches to
URL string `json:"url" protobuf:"bytes,1,opt,name=url"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor - do we want document how these are matched?

want: true,
},
}
for _, tt := range tests {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could simply this test to two lines, as any field other than EnableLFSshould not matter

r := q.Creds

if r.URL == "" {
return nil, status.Errorf(codes.InvalidArgument, "must specify URL")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

// repo and evaluate the results. Unless forceRefresh is set to true, the
// result may be retrieved out of the cache.
func (s *Server) getConnectionState(ctx context.Context, url string, forceRefresh bool) appsv1.ConnectionState {
if !forceRefresh {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need force refresh? I'm worried that we're using the wrong key for the correction state.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be useful when you change repository credentials, you can see whether the change was successful or not instantly. Credentials aren't (can't be) checked for validity.

The other possibility would be to invalidate the cache on connection state for every repository that matches the credentials' URL prefix, when the credentials change.

if err != nil {
return nil, err
}
if repoCreds != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this func accepts nil? So no need to guard.

@alexec alexec added this to the v1.4 milestone Oct 10, 2019
@alexec
Copy link
Contributor

alexec commented Oct 16, 2019

This has been approved but needs to be sync'd with master. @jannfis do you want to do this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants