GitHub-Actions
GitHub-Actions is a managed CI/CD offering integrated into GitHub. For standardisation and re-use within Gardener-Project, we maintain some re-usable Actions and Workflows (kept in cc-utils repository). Those offer functionality similar to Concourse-Pipeline-Template. This includes integration with OCM (Open Component Model), as well as release (notes) handling.
To improve security posture, we make use of trustbased-authentication, and avoid usage of static credentials where possible.
Migration from Concourse-Pipelines
The default pipeline setup for Concourse-Pipelines consists of three pipelines:
head-update (run for certain branches - typically default + release-branches)
pull-request (run for pullrequests)
release (manually triggered to publish new releases)
This is migrated to workflows of the following layout:
.github/workflows/build.yaml # shared; called by other workflows
.github/workflows/release.yaml # for manually triggering releases
.github/workflows/non-release.yaml # for triggering upon head-updates / pullrequests
Branch-Protection -> Rulesets
Most repositories use branch-protections to forbid directly pushing to a branch. Some pipelines, most prominently release-pipelines (which push release- and “bump”-commits), need to circumvent those rules. As we want to avoid using static credentials (for Service-Accounts w/ owner-permissions), we use a GitHub-App for granting such permissions more fine-granular.
However, as discussed here, it is only
possible to grant exceptions (or “bypassers”, as GitHub Rulesets call them) to branch protections
if using the more modern Rulesets
. Hence, as part of migration to GitHub-Actions, it is necessary
to migrate branch-protections to rulesets.
Note
It is important to no longer use “classical” branch protections after migration of
release-pipeline to GitHub-Actions. Configure any protection-rules using the more modern
Rulesets
, instead. The latter are a superset to branch-protections w.r.t. configuration
options.
Pull-Requests from forked Repositories
To mitigate harm from malicious Pull-Requests, GitHub-Actions-Workflow-Runs are run with restricted
privileges. If using pull_request
as pipeline-trigger, corresponding workflow-runs will only have
readonly-access to target-repository. This prevents such runs to push build artefacts, such as
OCI-Images or Helmcharts (to OCI-Registries).
As an alternative, there is the pull_request_target
trigger, which does not have this limitation.
However, by default, thus-triggered runs will be based on the pull-request’s target repository,
i.e. the actual changes proposed by a Pull-Request will not be visible to the pipeline-run.
For the latter case, there is the trusted-checkout action, which will circumvent this limitation, and explicitly checkout commits from trusted pullrequests. Pullrequests are considered to be trusted, if
the fork’s owner is the same as the target-repository (i.e. a fork within the same organisation)
OR - the pullrequest-author is either of:
COLLABORATOR
CONTRIBUTOR
MEMBER
(org-member)
OWNER
(repository-owner)
the pullrequest has a certain label (default:
reviewed/ok-to-test
) set
The preferred approach (because it will also work for first-time contributors) is using “label-based trust”.
Warning
For pullrequests that are not considered to be trusted, the workflow-run will still be executed. However, re-usable workflows from cc-utils will not attempt to push build-results, nor will the run be based on the changes from the pullrequest, which may be unintuitive.
In such cases, a warning is emitted into the pipeline-run’s summary.
Note
There are the following “autor-associations” a pullrequest author can have:
association |
explanation |
---|---|
COLLABORATOR |
Author has been invited to collaborate on the repository |
CONTRIBUTOR |
Author has previously committed to the repository |
FIRST_TIMER |
Author has not previously committed to GitHub |
FIRST_TIME_CONTRIBUTOR |
Author has not previously committed to the repository |
MANNEQUIN |
Author is a placeholder for an unclaimed user |
MEMBER |
Author is a member of the organization that owns the repository |
NONE |
Author has no association with the repository |
OWNER |
Author is the owner of the repository. |
When to use what
If a workflow does not need to publish changes from pullrequests, use on.pull_request
.
Otherwise, use on.pull_request_target
. In this case, consistently use trusted-checkout
instead
of actions/checkout
.
Warning
If using pull_request_target
, special care needs to be done to catch malicious changes,
especially such changes that are done in buildscripts.
Example configuration for label-based trust
If privileged pipelines are needed, use the following event-trigger:
on:
pull_request_target:
types:
- labeled
jobs:
example:
# the left condition (!= labeled) is only needed, if different triggers (e.g. push) are
# used.
# it is important to add the explicit check for label's name to prevent accidental
# triggering (e.g. from gardener-robot setting initial set of labels)
if: ${{ github.event.action != 'labeled' || github.event.label.name == 'revieved/ok-to-test' }}
permissions:
pull-requests: write # needed so trusted-checkout can remove trusted-label
# caveat: also needs to be set for all called workflows
# that use trusted-checkout (action)
...
The following workflow can be added for convenience:
# pullrequest-trust-helper.yaml
on:
pull_request_target:
types:
- opened
- edited
- reopened
- synchronize
jobs:
pullrequest-trusted-helper:
permissions:
pull-requests: write
secrets: inherit # access to `GitHub-Actions`-App is needed to read teams
uses: gardener/cc-utils/.github/workflows/pullrequest-trust-helper@master
with:
# members will be trusted (-> get okay-to-test-label automatically)
trusted-teams: 'first-team,second-team'
Caveats
Regardless which of on.pull_request
or on.pull_request_target
is used, workflow-runs will
always be based on target-repository’s local workflow- and actions-definitions.
Note
Be sure to grant pull-requests: write
-permission to all workflows called from
pull_request_target-event (this is needed so trusted-checkout action is able to remove
trusted-label).