runatlantis / atlantis

Terraform Pull Request Automation
https://www.runatlantis.io
Other
7.51k stars 1.02k forks source link

GitHub App credentials Cache rather than Store and multiple Orgs #4704

Open bdellegrazie opened 1 week ago

bdellegrazie commented 1 week ago

Community Note


Describe the user story

As a system operator I want Atlantis to adapt the Github App integration to use Git's credential cache rather than the Git's credential store.

Describe the solution you'd like

Assumptions

Solution

  1. Use the cache helper instead of store as this supports individual token expiry, as well as the cache expiry. An end user may want to use store for other reasons but this should not be forced.
  2. Instead of writing the credentials to the /home/atlantis/.git-credentials file, invoke git credential approve, supplying the url, username, password (token) and password_expiry_utc on stdin as per the documentation.

The Git credential protocol is quite simple and already supports token expiry. If this were used, the cache helper would automatically expire the token when necessary or when overwritten by Atlantis with a new token. Essentially this is leveraging Git credential protocol to minimise the amount of work being done by Atlantis and leaning on Git to do some of the heavy lifting.

A possible extension to this would help support multiple organisations (or owners) with a single Github App. Create a custom git credentials helper that, for a specific domain (org/owner):

  1. Generates a JWT token from existing App ID (or Client ID) and Private Key.
  2. If you don't have an Installation ID for the organisation (or owner):
    • Use JWT token to get installation Id from GitHub API
  3. Request an access token using the JWT token and Installation Id. Output the url, username (app slug), password (token), expiry time (as UTC seconds) This helper would be configured at the org level in Git, e.g.:
    [credential "https://github.com/exampleOrg/"]
        useHttpPath = true
        helper = github-app <ClientId|AppID> <path_to_private_key> exampleOrg

    When combined with the cache helper - this minimises GitHub API calls and simplifies integration with tools like Terraform etc.

Background Git has multiple credential helpers, the two installed with Git include:

Git custom credential helpers are also possible The protocol used by Git Credential Helpers is quite simple.

The current Github App mechanism involves configuring Git by:

  1. Using the store credential helper as a default
  2. Forcing Git to use https rather than ssh protocol via a url.*.insteadOf configuration property.
  3. Periodically writing the Github App's default installation access token to /home/atlantis/.git-credential

In terms of Git configuration, the default behaviour (when using GitHub App) looks like this in /home/atlantis/.gitconfig:

[credential]
    helper = store
[url "https://x-access-token@github.com"]
    insteadOf = ssh://git@github.com

And /home/atlantis/.git-credential will look like:

https://x-access-token:<some_token>@github.com

Describe the drawbacks of your solution

More reliant on Git as a tool, but the integration feels less intrusive and allows the configuration to be overridden by the end user if it is not suitable. Also allows use of multiple organisations with a single GitHub App.

Moving the token generation away from Atlantis is not suitable for the primary organisation as interaction with PRs etc is needed, but for supplementary organisations it makes it much easier to allow Git based access to the executing processes - e.g. Terraform / Terragrunt etc.

Describe alternatives you've considered

None at this time.