Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Argo CD Service Account / Local Users #3185

Closed
jessesuen opened this issue Mar 3, 2020 · 7 comments · Fixed by #3215
Closed

Argo CD Service Account / Local Users #3185

jessesuen opened this issue Mar 3, 2020 · 7 comments · Fixed by #3215
Labels
enhancement New feature or request

Comments

@jessesuen
Copy link
Member

jessesuen commented Mar 3, 2020

Summary

Argo CD should introduce service accounts for the purposes of automation/API access. This is a similar request for local users, so we should consider how both use cases might be solved using the same mechanism.

Motivation

Similar to project tokens, there is a use case where a service account is needed be used by automation to perform things like:

  • cluster registration/deregistration
  • repo registration/deregistration
  • project creation/deletion
  • other maintenance tasks (e.g. read only on all applications)

The built-in admin account is not well suited for this since:

  1. it is a two step auth process: create a session JWT using username/password, and then perform the API call with the returned JWT
  2. admin requires full privileges, and cannot be limited
  3. users desire multiple service accounts for different purposes and privileges
  4. the JWT lifecycle associated with login, cannot be controlled easily (e.g. a UI to generate new JWTs, revoke old ones, etc...)

Project roles are also not suited, because they can only operate on applications within the project, and not control clusters, repos, projects.

Proposal

Argo CD should introduce service accounts, where RBAC privileges can be limited for that account. Service accounts should be able to generate long-lived JWTs for API access. This feature closely overlaps with the request for "local users", so I think service accounts could potentially simply equate to local users, with some controls on whether or not the user can login with a username/password vs. only API keys.

A rough draft of how this might be configured could be in a K8s secret (e.g. a new argocd-accounts secret):

stringData:
  # Example of an service account, autouser, which would be used for automation
  # This account cannot login via username/password, but API keys (JWTs) can be generated for it
  # Could also introduce fields which enforce a max expiration
  accounts.autouser.apiKey: "true"
  accounts.autouser.apiKeyExpiration: 1d

  # Example of a local user, alice, which can login using username/password only.
  # The JWTs generated for local users during username/password login, should always
  # have an expiration, otherwise session tokens would essentially act as an infinite API key
  accounts.alice.password: <bcrypt hash>
  accounts.alice.passwordMtime: <updated during password change>

  # Example of local user, bob, which can login using username/password,
  # but also and generate long-lived JWTs.
  accounts.bob.apiKey: "true"
  accounts.bob.password: <bcrypt hash>
  accounts.bob.passwordMtime: <updated during password change>

In the above example, autouser, alice, and bob would be used as the sub field of the JWT, and is what the argocd-rbac-cm would use in the RBAC rules.

Additional requirements:

  • A new RBAC control for account will probably be need to be introduced, so that a human/admin/SSO user would be able to generate JWTs for a different account, if they had privileges.

  • The identifiers of all vended API keys for an account, should be persisted somewhere (similar to project tokens), so that they can be revoked if necessary.

@jessesuen jessesuen added the enhancement New feature or request label Mar 3, 2020
@jessesuen
Copy link
Member Author

jessesuen commented Mar 5, 2020

Also, users should be able to be disabled and enabled:

stringData:
  accounts.alice.enabled: "false"
  accounts.alice.password: <bcrypt hash>
  accounts.alice.passwordMtime: <updated during password change>

For consistency, I think the recently added option to disable admin should be changed to follow this convention:

stringData:
  admin.enabled: "false"
  admin.password: <bcrypt hash>
  admin.passwordMtime: <updated during password change>

@alexmt
Copy link
Collaborator

alexmt commented Mar 5, 2020

Another proposal regarding where local account should be stored:

I guess the new argocd-accounts secret is proposed to avoid too many keys in argocd-secret, right? This still might be not enough because even in a separate secret there might be too many keys, so it will be painful to manage and we might hit 1mb limit. Storing each user in a separate secret is another extreme - it is painful to manage.

I propose to allow storing any settings in any secret as long as it has app.kubernetes.io/name: argocd-secret label. In this case users can keep using argocd-secret as usual an introduce more secrets later when needed.

@jessesuen
Copy link
Member Author

jessesuen commented Mar 5, 2020

For MVP, we need to support:

  • Declarative account management via a secret using the proposed syntax
  • Introduction of RBAC for a new accounts resource
  • API endpoint & CLI support for generating/revoking JWTs (honoring RBAC of accounts and probably accounts/token resource)
    • e.g. argocd account generate-token and argocd account generate-token --account alice

When JWTs are generated, we need to persist the JWT reference somewhere so that it can be revoked. This will probably be just an adjacent key in the secret

stringData:
  #accounts.autouser.enabled: "false" # operator managed key
  accounts.autouser.apiKey: "true" # operator managed key
  accounts.autouser.tokens: "[\"<tokenid-1>\",\"<tokenid-2>\"]" # auto-generated key

In the future, we could support:

  • API/CLI/UI support for user management

I think we can continue to argocd-secret for now, and in the future, we could always decide to merge secrets using your proposal, if local accounts becomes too large for the secret.

@jessesuen
Copy link
Member Author

jessesuen commented Mar 6, 2020

Thinking about this some more, managing accounts via a secret, may not be the best experience for operators, since it is common to have a separate mechanism for managing secrets with GitOps. For non-sensitive configuration, it is preferable to manage it via git (e.g. to allow pull requests to add/remove/disable accounts). Really, the only thing that needs to be in the secret, is the bcrypt hash of the password. Everything else is configuration and not sensitive data.

This is might not be the best solution, but perhaps the configuration should be split into argocd-cm and argocd-secret.

argocd-cm.yaml:

data:
  # The accounts.XXX entry is a list of the capabilities of that user
  accounts.alice: login
  accounts.bob: login, apiKey
  accounts.bob.enabled: "false"
  accounts.autouser: apiKey

argocd-secret.yaml:

stringData:
  # Everything in the secret is typically generated by API server
  accounts.alice.password: <bcrypt hash>
  accounts.alice.passwordMtime: <updated during password change>
  accounts.bob.password: <bcrypt hash>
  accounts.bob.passwordMtime: <updated during password change>
  accounts.bob.tokens: "[\"<tokenid-1>\",\"<tokenid-2>\"]" 
  accounts.autouser.tokens: "[\"<tokenid-1>\",\"<tokenid-2>\"]" 

The above configuration would result in three users:

  1. alice is a human user which can login via username/password
  2. bob is also a human user who can generate API keys, but whose account is currently disabled
  3. autouser is an automation user, which can perform API requests using the tokens specified in the list.

@cyrus-mc
Copy link

Trying to use this feature. Created a local/service account

› argocd account get --account ci
Name:               ci
Enabled:            true
Capabilities:       apiKey

Tokens:
ID                                    ISSUED AT                  EXPIRING AT
497d112c-6853-4d0c-xxxxxxx  2020-12-11T10:12:05-08:00  never

I then try to authenticate with that user using the token

argocd login argocd.xxxxx --name ci --auth-token 497d112c-6853-4d0c-xxxxx

But I am then asked for the username and password.

@abdennour
Copy link

@cyrus-mc please make sure to have the latest argocd CLI version .

@SamDecrock
Copy link

SamDecrock commented Feb 10, 2021

@cyrus-mc You don't have to login when using tokens. Simply provide the token when running the command. For example:

argocd cluster add <cluster-name> \
    --server <your-server> \
    --auth-token <your-token>

Also make sure your ci user has enough rights. This means you'll probably have to update the argocd-rbac-cm ConfigMap (kubectl -n argocd edit cm argocd-rbac-cm) so that it contains:

data:
  policy.csv: |
    g, ci, role:admin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants