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

[RFC-007] Implement GitHub app authentication for git repositories. #1647

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

dipti-pai
Copy link
Member

  • API change to add new github provider field in GitRepository spec.
  • Controller change to use the GitHub authentication information specified in .spec.secretRef to create the auth options to authenticate to git repositories when the provider field is set to github
  • Tests for new github provider field
  • Updated docs to use GitHub Apps for authentication in source-controller.

@dschniepp
Copy link

Thank you for picking up this topic. Can we also add documentation for the use with GitHub Enterprise?

Copy link
Contributor

@darkowlzz darkowlzz left a comment

Choose a reason for hiding this comment

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

Did some basic testing and it worked as expected for the happy path

spec:
  interval: 5m0s
  provider: github
  ref:
    branch: main
  secretRef:
    name: github-sa
  timeout: 60s
  url: https://github.com/darkowlzz/test-1
status:
  artifact:
    digest: sha256:4166a3310c4f57471a5cfa2910475e4d47874920d7c156f656b7e70c01adcd2e
    lastUpdateTime: "2024-12-03T21:09:21Z"
    path: gitrepository/default/test-1/a4f6eca644dadd9112ff3d93c99eda63eeca949a.tar.gz
    revision: main@sha1:a4f6eca644dadd9112ff3d93c99eda63eeca949a
    size: 4083
    url: http://:0/gitrepository/default/test-1/a4f6eca644dadd9112ff3d93c99eda63eeca949a.tar.gz
  conditions:
  - lastTransitionTime: "2024-12-03T21:09:21Z"
    message: stored artifact for revision 'main@sha1:a4f6eca644dadd9112ff3d93c99eda63eeca949a'
    observedGeneration: 1
    reason: Succeeded
    status: "True"
    type: Ready
  - lastTransitionTime: "2024-12-03T21:09:21Z"
    message: stored artifact for revision 'main@sha1:a4f6eca644dadd9112ff3d93c99eda63eeca949a'
    observedGeneration: 1
    reason: Succeeded
    status: "True"
    type: ArtifactInStorage
  observedGeneration: 1

Left some comments, suggestions a few improvements.

docs/spec/v1/gitrepositories.md Outdated Show resolved Hide resolved
docs/spec/v1/gitrepositories.md Outdated Show resolved Hide resolved
docs/spec/v1/gitrepositories.md Outdated Show resolved Hide resolved
docs/spec/v1/gitrepositories.md Outdated Show resolved Hide resolved
docs/spec/v1/gitrepositories.md Outdated Show resolved Hide resolved
AzureOpts: []azure.OptFunc{
azure.WithAzureDevOpsScope(),
},
}
case sourcev1.GitProviderGitHub:
Copy link
Contributor

@darkowlzz darkowlzz Dec 3, 2024

Choose a reason for hiding this comment

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

Unlike Azure, GitHub provider requires a secret reference containing the identity details. Currently, not providing any secret ref results in the following state:

status:
  conditions:
  - lastTransitionTime: "2024-12-03T21:11:55Z"
    message: building artifact
    observedGeneration: 1
    reason: ProgressingWithRetry
    status: "True"
    type: Reconciling
  - lastTransitionTime: "2024-12-03T21:11:55Z"
    message: 'failed to checkout and determine revision: invalid app id, err: strconv.Atoi:
      parsing "": invalid syntax'
    observedGeneration: 1
    reason: GitOperationFailed
    status: "False"
    type: Ready
  - lastTransitionTime: "2024-12-03T21:11:50Z"
    message: 'failed to checkout and determine revision: invalid app id, err: strconv.Atoi:
      parsing "": invalid syntax'
    observedGeneration: 1
    reason: GitOperationFailed
    status: "True"
    type: FetchFailed
  observedGeneration: -1

and similar logs

{"level":"error","ts":"2024-12-04T02:42:13.583+0530","msg":"Reconciler error","controller":"gitrepository","controllerGroup":"source.toolkit.fluxcd.io","controllerKind":"GitRepository","GitRepository":{"name":"test-1","namespace":"default"},"namespace":"default","name":"test-1","reconcileID":"eaa78267-8c4a-4d85-9779-05226fff0b2b","error":"failed to checkout and determine revision: invalid app id, err: strconv.Atoi: parsing \"\": invalid syntax"}

I don't think these are friendly enough for the new users. Also, this is a bad configuration and should result in Stalled state.

❗ NOTE: The following suggestion can be ignored. See the next comment for another suggestion with considerations of more scenarios.

getAuthOpts() returns error that's interpreted as a generic error to attempt a retry. Rather than trying to return a typed error from getAuthOpts() and then try to return the appropriate error, it may be better to create a new function for just validating the provider related configuration (just for GitHub for now, but GitLab too in the future) and any error returned from it should result in a stalling error. We can call this function just before

authOpts, err := r.getAuthOpts(ctx, obj, *u)
.

Copy link
Contributor

Choose a reason for hiding this comment

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

This was discussed in the dev meeting today and we have two more scenarios related to this that should have validation:

  • When a secret ref is provided but the provider is not set, and the secret contains github app data, it should result in a stalling failure with error saying that the secret contains github app data, please set the provider to github. It may be better to first check if the repository host is github.com before checking the secret.
  • When a secret ref is provided and the provider is set to github, but the secret does not contain github app data fields, it should result in a retryable failure (generic error) with error saying that the secret must have the github app data. This is a validation of the provided secret content. Because we don't watch the secret, we don't have a way to get notified when the secret is fixed. We have to fail and retry, hoping that eventually the secret will be fixed.

With this, I'd backtrack a bit. Initially, I was recommending to validate that the secret ref is provided when github is the provider before getAuthOpts() as there was no secret involved. But with the two scenarios above, the secret content needs to be analyzed. It would be better to get the secret just once, which we already have in getAuthOpts().
I think we can change getAuthOpts() similar to the other functions, like verifySignature(), fetchIncludes() and others where the errors and conditions are set within these functions. The caller just returns the result. That way, we remain consistent with what's done in other functions.

Copy link
Member Author

Choose a reason for hiding this comment

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

Improved the error messaging for the following 4 scenarios, added unit tests and tested with SC.

  1. Provider: github, no secretRef in gitRepository spec
    Result: Stalling error, error message: secretRef with github app data must be specified when provider is set to github
Name:         ghapp-repo
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  source.toolkit.fluxcd.io/v1
Kind:         GitRepository
Metadata:
  Creation Timestamp:  2024-12-05T20:24:11Z
  Finalizers:
    finalizers.fluxcd.io
  Generation:        1
  Resource Version:  17094229
  UID:               67a75e2e-55f6-4e60-bb04-187e0698a5bb
Spec:
  Interval:  1m
  Provider:  github
  Ref:
    Branch:  main
  Timeout:   60s
  URL:       https://github.com/dp-flux-testing/dp-flux-testing.git
Status:
  Conditions:
    Last Transition Time:  2024-12-05T20:24:11Z
    Message:               secretRef with github app data must be specified when provider is set to github
    Observed Generation:   1
    Reason:                AuthenticationFailed
    Status:                True
    Type:                  Stalled
    Last Transition Time:  2024-12-05T20:24:11Z
    Message:               secretRef with github app data must be specified when provider is set to github
    Observed Generation:   1
    Reason:                AuthenticationFailed
    Status:                False
    Type:                  Ready
    Last Transition Time:  2024-12-05T20:24:11Z
    Message:               secretRef with github app data must be specified when provider is set to github
    Observed Generation:   1
    Reason:                AuthenticationFailed
    Status:                True
    Type:                  FetchFailed
  Observed Generation:     1
Events:
  Type     Reason                Age   From               Message
  ----     ------                ----  ----               -------
  Warning  AuthenticationFailed  28s   source-controller  secretRef with github app data must be specified when provider is set to github
  1. provider: github, secretRef is present, but secret is not present
    Result: Generic error with retry.
Name:         ghapp-repo
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  source.toolkit.fluxcd.io/v1
Kind:         GitRepository
Metadata:
  Creation Timestamp:  2024-12-05T20:24:11Z
  Finalizers:
    finalizers.fluxcd.io
  Generation:        2
  Resource Version:  17095637
  UID:               67a75e2e-55f6-4e60-bb04-187e0698a5bb
Spec:
  Interval:  1m
  Provider:  github
  Ref:
    Branch:  main
  Secret Ref:
    Name:   ghapp-secret
  Timeout:  60s
  URL:      https://github.com/dp-flux-testing/dp-flux-testing.git
Status:
  Conditions:
    Last Transition Time:  2024-12-05T20:29:13Z
    Message:               building artifact
    Observed Generation:   2
    Reason:                ProgressingWithRetry
    Status:                True
    Type:                  Reconciling
    Last Transition Time:  2024-12-05T20:29:13Z
    Message:               failed to get secret 'default/ghapp-secret': secrets "ghapp-secret" not found
    Observed Generation:   2
    Reason:                AuthenticationFailed
    Status:                False
    Type:                  Ready
    Last Transition Time:  2024-12-05T20:29:02Z
    Message:               failed to get secret 'default/ghapp-secret': secrets "ghapp-secret" not found
    Observed Generation:   2
    Reason:                AuthenticationFailed
    Status:                True
    Type:                  FetchFailed
  Observed Generation:     1
Events:
  Type     Reason                Age               From               Message
  ----     ------                ----              ----               -------
  Warning  AuthenticationFailed  5m9s              source-controller  secretRef with github app data must be specified when provider is set to github
  Warning  AuthenticationFailed  7s (x5 over 18s)  source-controller  failed to get secret 'default/ghapp-secret': secrets "ghapp-secret" not found
  1. provider: github, associated secret has missing app ID/app Installation ID/private key.
    Result: Generic error, validation in pkg code during checkout.
Name:         ghapp-repo
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  source.toolkit.fluxcd.io/v1
Kind:         GitRepository
Metadata:
  Creation Timestamp:  2024-12-05T20:24:11Z
  Finalizers:
    finalizers.fluxcd.io
  Generation:        2
  Resource Version:  17097352
  UID:               67a75e2e-55f6-4e60-bb04-187e0698a5bb
Spec:
  Interval:  1m
  Provider:  github
  Ref:
    Branch:  main
  Secret Ref:
    Name:   ghapp-secret
  Timeout:  60s
  URL:      https://github.com/dp-flux-testing/dp-flux-testing.git
Status:
  Conditions:
    Last Transition Time:  2024-12-05T20:35:25Z
    Message:               building artifact
    Observed Generation:   2
    Reason:                ProgressingWithRetry
    Status:                True
    Type:                  Reconciling
    Last Transition Time:  2024-12-05T20:35:25Z
    Message:               failed to checkout and determine revision: private key must be provided to use github app authentication
    Observed Generation:   2
    Reason:                GitOperationFailed
    Status:                False
    Type:                  Ready
    Last Transition Time:  2024-12-05T20:35:25Z
    Message:               failed to checkout and determine revision: private key must be provided to use github app authentication
    Observed Generation:   2
    Reason:                GitOperationFailed
    Status:                True
    Type:                  FetchFailed
  Observed Generation:     1
Events:
  Type     Reason                Age                    From               Message
  ----     ------                ----                   ----               -------
  Warning  AuthenticationFailed  13m                    source-controller  secretRef with github app data must be specified when provider is set to github
  Warning  AuthenticationFailed  7m43s (x7 over 8m30s)  source-controller  failed to get secret 'default/ghapp-secret': secrets "ghapp-secret" not found
  Warning  GitOperationFailed    6m55s                  source-controller  failed to checkout and determine revision: app ID must be provided to use github app authentication
  Warning  GitOperationFailed    5m19s                  source-controller  failed to checkout and determine revision: app installation ID must be provided to use github app authentication
  Warning  GitOperationFailed    2m7s                   source-controller  failed to checkout and determine revision: private key must be provided to use github app authentication
  1. secret contains githubAppID and provider not set.
    Result: Stalling error indicating provider is not set to github

Notes:

  • As discussed in the dev meeting, checking only for github App ID presence to detect that intent is to use github app authentication.
  • Did not include hostname validation here since for Github Enterprise Server, the hostname does not necessarily contain 'github'. In any case the secret should not contain githubAppID as data unless intent was to use github app authentication. Let me know thoughts.
Name:         ghapp-repo
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  source.toolkit.fluxcd.io/v1
Kind:         GitRepository
Metadata:
  Creation Timestamp:  2024-12-05T20:24:11Z
  Finalizers:
    finalizers.fluxcd.io
  Generation:        3
  Resource Version:  17099528
  UID:               67a75e2e-55f6-4e60-bb04-187e0698a5bb
Spec:
  Interval:  1m
  Ref:
    Branch:  main
  Secret Ref:
    Name:   ghapp-secret
  Timeout:  60s
  URL:      https://github.com/dp-flux-testing/dp-flux-testing.git
Status:
  Artifact:
    Digest:            sha256:312bafaed0040134c57615608de187def57d97d4db09e46a3d64562b6f9c96ed
    Last Update Time:  2024-12-05T20:41:50Z
    Path:              gitrepository/default/ghapp-repo/f3e6c65b2ae4e0f333cf317143b20efcc83400a0.tar.gz
    Revision:          main@sha1:f3e6c65b2ae4e0f333cf317143b20efcc83400a0
    Size:              470
    URL:               http://source-controller.source-system.svc.cluster.local./gitrepository/default/ghapp-repo/f3e6c65b2ae4e0f333cf317143b20efcc83400a0.tar.gz
  Conditions:
    Last Transition Time:  2024-12-05T20:43:18Z
    Message:               secretRef 'default/ghapp-secret' has github app data but provider is not set to github
    Observed Generation:   3
    Reason:                AuthenticationFailed
    Status:                True
    Type:                  Stalled
    Last Transition Time:  2024-12-05T20:43:18Z
    Message:               secretRef 'default/ghapp-secret' has github app data but provider is not set to github
    Observed Generation:   3
    Reason:                AuthenticationFailed
    Status:                False
    Type:                  Ready
    Last Transition Time:  2024-12-05T20:43:18Z
    Message:               secretRef 'default/ghapp-secret' has github app data but provider is not set to github
    Observed Generation:   3
    Reason:                AuthenticationFailed
    Status:                True
    Type:                  FetchFailed
    Last Transition Time:  2024-12-05T20:41:50Z
    Message:               stored artifact for revision 'main@sha1:f3e6c65b2ae4e0f333cf317143b20efcc83400a0'
    Observed Generation:   2
    Reason:                Succeeded
    Status:                True
    Type:                  ArtifactInStorage
  Observed Generation:     3

@stefanprodan
Copy link
Member

stefanprodan commented Dec 6, 2024

@dipti-pai please rebase with main, it contains the latest auth and git packages with GitHub App support.

- API change to add new `github` provider field in `GitRepository` spec.
- Controller change to use the GitHub authentication information specified in `.spec.secretRef` to create the auth options to authenticate to git repositories when the `provider` field is set to `github`,
- Tests for new `github` provider field
- Updated docs to use GitHub Apps for authentication in source-controller.

Signed-off-by: Dipti Pai <[email protected]>
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