In January, we received a stark reminder that the security of our CI/CD pipelines is a really big deal. Your CI/CD pipeline needs the power to deploy code into your infrastructure, but deployment requires a high level of privilege, which often includes the ability to SSH into servers, to talk to APIs, to push code into containers, and to spin infrastructure up and down. If your CI/CD pipeline gets compromised, those privileges fall into the hands of an adversary… which means that an adversary can push malicious code into your infrastructure… which is ~about the worst~ thing that can happen.
In other words, your CI/CD pipeline is a security risk for your supply chain and in the eyes of an adversary, is a single point of compromise.
Unfortunately, reasoning about the security of your CI/CD pipeline is not always easy. These build pipelines are often complicated. When we ask folks, “What kind of credentials do your build pipelines have?” We very often hear, “Hmm, I’m not sure, let me check.” This lack of visibility creates a suite of security risks.
Fortunately, with BastionZero, we make it easy to secure your CI/CD pipelines.
In this blog, I’ll explain how to use BastionZero (BZ) Service Accounts paired with our Github Actions integration to secure your CI/CD pipeline’s access to your infrastructure.
Key Aspects to Our Approach
- Go trustless: Eliminate single points of compromise. Instead of entrusting your build pipeline with all of your secrets, BastionZero Service Accounts require two roots of trust to authenticate a CI/CD runner before the runner is able to push code into your infrastructure, and a compromise of the CI/CD pipeline does not enable the adversary to authenticate to these two roots of trust.
- Go passwordless! Our design philosophy is to limit the headaches associated with storing many different server access credentials in your CI/CD runner. [This should be familiar to those teams who spent days or weeks urgently rotating credentials following the CircleCI breach.] Instead, the runner just needs credentials to log in to BastionZero, which makes credential management and rotation simpler and easier.
- Centralize policy. You might have several build pipelines that need access to different parts of your infrastructure, across different clouds and data centers. With BastionZero, you can use our centralized policy manager to map which build pipelines have access to which infrastructure, when, and for how long.
- Gain visibility. BastionZero will log each access your CI/CD runner makes to your infrastructure, as well as the commands that it runs. This is a great way to identify a rogue deployment or to track unexpected behavior from your pipeline. You can also get ahead of compliance and security questionnaires that ask about the security of your software supply chain.
How It Works
With BZ Service Accounts, your CI/CD pipeline runner will only be able to push code to your infrastructure if (1) there was a valid GitHub Action authorizing the CI/CD tool to access the deployment target, and (2) the runner has properly authenticated with BastionZero. To do this, the runner has access to an authentication factor that allows it to authenticate to BastionZero (you could store this authentication factor in a vault, or in the CircleCI SaaS, which would then hand it to the runner when it spins up and provisions the runner).
The key point is that the authentication factor used with BastionZero is not shared with GitHub.
As with everything in BastionZero, you will eliminate single points of compromise by having two roots of trust. One root of trust is the BastionZero cloud service. And the other root of trust is an independent part of your CI/CD pipeline -- in these examples we’ll use GitHub (actually, GitHub Actions). The key idea here is that one root of trust is compromised, the other is still there to protect you. In this way, we can enable a type of multi factor authentication within your CI/CD pipeline.
How This Improves Security
First, let’s walk through what happens if the authentication factor the runner uses with BastionZero is stolen. [For example, if CircleCI’s SaaS service is hacked.] Well, if GitHub Actions is not hacked, then the runner still can’t push code to your infrastructure. That’s because the runner doesn’t have the credentials needed to initiate a GitHub Action. And the attacker can’t initiate a valid GitHub Action that authorizes the runner to push the code without also compromising GitHub Actions.
At this point you might say, “OK, so why not just use GitHub Actions and call it a day?”
As a first point, our solution lets organizations continue to use existing workflows and CI/CD processes, without having to trash everything and move everything to GitHub Actions. With BastionZero’s approach, you can maintain your existing CI/CD pipeline. All you have to do is remove the access credentials from your CI/CD runner and replace them with our command line interface, the Zero Trust Command Line Interface (the zli). You also set up a simple GitHub Actions script to add GitHub as a second root of trust for your CI/CD pipeline, and you are ready to go.
Whenever the runner wants to run a job, the centralized policy manager in the BastionZero cloud service determines which targets the runner has access to, when and for how long. Like everything else in BastionZero, audit logs are collected for all commands that are run.
How to Set Up an Authorized Github Action
Check out our Github Actions guide to learn more about how to put this solution in place.
A video of the feature “in action” is available below: