Using Github Actions Securely
Github have recently released Actions, much like CircleCI and Travis, it makes it really easy to get up and running to Build, Test and Deploy your application. Unlike CircleCI and Travis, Actions allow you to easily reuse Actions via the Marketplace. This opens up some really nice ways of reusing common functionality, but much like Docker images, chef recipes, npm packages or similar, you have to be conscious of the source of the component, and whether it's safe to bring in to your application/environment.
CI/CD tools are trusted with some of the most critical secrets, AWS keys, source control access. Not to mention that they can be used to inject compromised code into built artefacts. Security really needs to be considered when re-using Actions. Always check:
- The source (Actions don't seem to support verification yet)
- You can link the Action to a version of the code
- Any Docker containers used are also safe
- You can see the code and ensure it does what it should do
And you should check this every version upgrade - because you really don't want to risk bringing in dangerous code into your Workflow.
Still despite all these checks, the way Github Releases work (and the Marketplace), you could still have an issue.
Third Party Actions - Versioning Vulnerable
One of the major differences of Github Actions is the support for reusable actions. These package up common tasks, so you can include and reference them easily. They're versioned and available for everyone to find in Github's Marketplace. They can do anything from building code, linting, testing, to deployment.
But the recommended way of including actions is currently a massive security vulnerability of your Action Workflow.
Take my action: https://github.com/marketplace/actions/serverlesscli
- name: serverless deploy
uses: tegud/serverless-github-action@1.52.0
with:
command: deploy
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
When included in your Workflow, with the correct secrets set, it will deploy your Serverless functions using the specified AWS credentials (don't commit your AWS keys folks).
But, there's a catch, I've specified I want to use version 1.52.0, I would expect this release to be immutable. If you want to see what happens when lots of people depend on an external dependency and for it to then disappear see the great NodeJS left pad debacle. But unfortunately, even worse than that is then allowing someone to replace the previous release with new code with the same version.
Which is possible with Github Actions.
- Create an action, release it to the market place (e.g. an-org/cool-action@v1)
- Create workflow which utilises an-org/cool-action@v1 (it may or may not receive/require sensitive secrets such as AWS keys)
- Commit new code to an-org/cool-action, which could: transmit secrets to external servers, modify code to inject vulnerabilities, track usage in ways not agreed by, ship code to external sources.
- Delete release & tag v1 on an-org/cool-action
- Create release using vulnerability injected code above with the same name/tag "v1"
- Trigger workflow, attacking code within the action will be executed.
7. And now I have your secret password.
The scope of attacks here is somewhat concerning. With the Serverless CLI example above, we've got someone's AWS credentials, and probably with a decent level of access to boot. But it could be even worse, the workflow could easily inject comprised code into an application before deployment, and enable worse privacy/data breaches, or crypto mining. The CI/CD pipeline is a key part of application build and deployment, making it potentially devastating to exploit, and here Github Actions are setting a best practice that encourage users to open themselves up to this sort of attack.
Github's response is to version using SHA instead of version number, so from our example above again:
- name: serverless deploy
uses: tegud/serverless-github-action@089a3603204affdd86da79e742fa520a6fe16d69
with:
command: deploy
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
This would be much harder to exploit. But that's not in their documentation, and it's not the examples you'll see in most the Marketplace either (it'd be remarkably hard to actually make it that the description in the market place as you don't know the SHA in advance).
It may be you can trust a Third Party Action vendor in the marketplace if they're "official" (Though it's early days, so there's no verification for official or not), but since a lot of these are open source project with multiple contributors, who take on additional contributors from the community, again is it worth the risk?
So don't use Actions?!
Github Actions are good, I'm using them, and I'm enjoying them overall, if you treat your CI/CD pipeline with the distrust it warrants (seriously, it's so important you know where the things you put in your pipeline come from!) then it's a serious alternative to CircleCI or Travis.
Hopefully Github will tighten up security around releases, and I can update this blog post in the future to say it's been fixed. But for now, be careful what actions you let into your workflows.