starter-workflows icon indicating copy to clipboard operation
starter-workflows copied to clipboard

Feature: add pinning variable

Open laurentsimon opened this issue 3 years ago • 15 comments

For security reasons, it's common practice to pin third-party action dependencies by hash in workflows. It's recommended in OSSF scorecard, for example. It helps avoid situation where a dependencies is compromised: if the dependency is pinned by version or latest or not pinned at all, a new version would be automatically picked up by the next workflow runs, leading to code execution.

Some starter workflows already follow this practice, e.g., https://github.com/actions/starter-workflows/blob/main/code-scanning/crunch42.yml#L43. There are many others that do so in this repo, which is great!

However, it may become cumbersome to maintain: a user who has previously submitted a starter-workflow will need to update the hashes once in a while. Usually, users do this by enabling tools like dependabot/renovabot on their own repo. To make the changes on the starter-workflow repo (here!), users now need to replicate the changes by submitting a PR to the starter-workflow repo. This is more work for both the repo owner and for the starter-workflow maintainers (PR reviews) each time dependabot/renovabot submits a PR on the original repo.

I wonder if it'd be useful to introduce a new variable like $hash or $pin, which could be used as follow in starter workflows:

        uses: some/action@$hash("3.*.*") // Substitute the variable with the commit hash of the latest version "3.X.Y" 
        uses: some/action@$hash("3.2.*") // Substitute the variable with the commit hash of the latest version "3.2.X" 

        uses: some/action@$pin("hash", "3.2.*") // Substitute the variable with the the latest version "3.2.X" 
        uses: some/action@$pin("version", "3.2.*") // Substitute the variable with the latest version "3.2.X" 

Alternatives considered: Configure dependabot on this repo. I don't this this would work because

  1. Dependabot only looks for workflows under .github/workflows, I suppose?
  2. Only the owners of the starter workflow can tell whether an update may break their action. So it seems wiser to let them configure which dependency version should work in the workflow.

laurentsimon avatar Dec 10 '21 16:12 laurentsimon

cc @josepalafox

laurentsimon avatar Dec 10 '21 16:12 laurentsimon

I think I missed an important requirement in my initial feature description: third-party actions are not allowed in the workflow, it seems. So we may simplify the feature by simply exposing a $last-release-hash for the starter action:

        uses: user/action@$last-release-hash

$last-release-hash would be substituted with the latest released version's hash. This way, when developers publish a new action (using Publish this Action to Marketplace), users who then enable this action via the market place would have the action pinned to the latest version's pin automatically.

laurentsimon avatar Dec 13 '21 16:12 laurentsimon

follow-up: some users may still want to pin by hash the GitHub actions that are used in the workflow. So my original description is still relevant.

laurentsimon avatar Dec 28 '21 17:12 laurentsimon

This issue has become stale and will be closed automatically within a period of time. Sorry about that.

github-actions[bot] avatar Mar 29 '22 04:03 github-actions[bot]

Please don't close this issue, @github-actions bot!

laurentsimon avatar Mar 29 '22 14:03 laurentsimon

Hey @laurentsimon, can you point us to an example of such pinned variables? Thanks

Phantsure avatar Apr 06 '22 06:04 Phantsure

sure, here are some examples: https://github.com/actions/starter-workflows/blob/main/code-scanning/apisec-scan.yml#L56 https://github.com/actions/starter-workflows/blob/main/code-scanning/scorecards.yml#L30

In accordance with https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-third-party-actions, Pin actions to a full length commit SHA.

Note that it would be even better if GitHub supported [email protected]:the_hash so it'd be more obvious which version the hash corresponds to (containers support something similar).

Today most users use a comment:

action@the_hash # v1.2.3

But dependabot does not update the comment when bumping hashes :/

laurentsimon avatar Apr 06 '22 16:04 laurentsimon

https://github.com/actions/starter-workflows/blob/main/code-scanning/apisec-scan.yml#L56

This is following the current convention by GitHub, right? Where can i find the actions written with hash pinned variable? Or is it a completely new concept for any provider?

Phantsure avatar Apr 07 '22 10:04 Phantsure

Right. My feature request is the following: every time an action workflow releases a new version, they need to send a PR to this repo to upload the hash pin. This is time consuming both for us (releasers) and you (you need to review pull requests).

What I'm proposing is the ability to define a variable in the starter-workflow to say "Please take the hash pin of the latest version of my action when the user uses the starter workflow template".

Today you have support for variables like $default-branch which is automatically set to the default branch of the user, but I'd like variables like $hash or $pin(...) to declare which hash should be automatically populated.

Does it help?

laurentsimon avatar Apr 07 '22 22:04 laurentsimon

Yeah. That does help.

Phantsure avatar Apr 08 '22 10:04 Phantsure

@laurentsimon while I completely agree to your assessment of the recurring effort needed to update the hash, any auto update of an action version can be a security hole for end user. Actions today recommends pinning to a hash so that a workflow uses a well known and tested third party action. Commit SHA is immutable but a release version is not immutable. Imagine a scenarios where a hacker gets access to a third party action (which does not follow all appropriate security supply chain procedures) and publishes a patch update with malicious code. A hash or pin functionality would automatically start using that new patch version's sha. PS: the same rule does not apply for any first party action as we do expect these actions to follow good security practices.

bishal-pdMSFT avatar Apr 09 '22 12:04 bishal-pdMSFT

What you describe only happens at first installation, so it's low risk. This is the way everything works today: package managers do this: on first installation you must trust the hash you get for your dependencies (go install, npm install, etc), ie Trust-On-First-Use. After that the hash will not change if it's pinned by hash (lock file)- which this proposal does not change. I'm only suggesting the first workflow installation takes the latest hash (as described by the authors) and hardcode it in the workflow, not that the workflow use a version to pin the action.

laurentsimon avatar Apr 11 '22 16:04 laurentsimon

What you describe only happens at first installation, so it's low risk. This is the way everything works today: package managers do this: on first installation you must trust the hash you get for your dependencies (go install, npm install, etc), ie Trust-On-First-Use.

Trust on first use is based on the testing done by package managers. They would do due diligence before consuming any third party action. But in case of starter workflows, I am not sure they would be expected to do due diligence, especially given that these workflows are "suggested" by GitHub. Mind that the moment they commit and push these workflows, they will get triggered and these third party actions will have access.

@azooinmyluggage any thoughts here?

bishal-pdMSFT avatar Apr 12 '22 05:04 bishal-pdMSFT

what do you mean by "testing done by package managers"?

"these third party actions will have access" I'm only suggesting a "pin variable" for the "main" action defined in the starter-workflow. For the scorecard starter-workflow, for example, it would be "ossf/scorecard-action".

My understanding is that the starter-workflow maintainers trust the authors of the actions to give them the hash pin for their action (I did this for the scorecard project myself many times). What's the difference with trusting them to say "take the hash for my latest version at first install" instead?

Today:

  1. Do you verify who sends the PR to update a starter-workflow?
  2. Do you check they are maintainers for the project's action?
  3. Do you verify the hash is from the main branch?

If you do that, great; but this can be automated. What else do you do?

Something else I want to point out is that users have dependbot installed. This means that existing users who have the action pinned by hash will receive updates anyway. The number of existing users is far greater than the number of users installing new starter-workflow on their repo. So if there's a risk of installing a malicious action, the existing user base matters more. If dependabot in unable to tell that a new version of an action is malicious, then all these users will be compromised. It does not matter what the original pin was.

There's a danger of making it harder for action maintainers to update their pin hash, and it may encourage them to use versions instead.

Just to be clear; I appreciate your questions and I think it's pretty useful to ask and discuss them. I'm only trying to see if we're decreasing usability for very little security gains.

laurentsimon avatar Apr 12 '22 15:04 laurentsimon

This issue has become stale and will be closed automatically within a period of time. Sorry about that.

github-actions[bot] avatar Aug 10 '22 04:08 github-actions[bot]

This issue has become stale and will be closed automatically within a period of time. Sorry about that.

github-actions[bot] avatar Nov 09 '22 04:11 github-actions[bot]

I would like to re-open this issue.

laurentsimon avatar Nov 22 '22 19:11 laurentsimon