Top Picks for Cloud Native Sessions at Oracle CloudWorld 2023
Blabla Free Post: These are just some of my (personal) top Oracle CloudWorld 20232 sessions I will have the chance to attend and speak at this ... Read More
Find out why Eclipsys has been named the 2023 Best Workplaces™ in Technology, Great Place to Work® Canada and named Canada’s Top SME Employers!
Learn more!This year I set a goal to explore and learn the most popular CI solutions like GitLab, including all cloud-native ones. My first pick had to be GitHub Actions, which I heard a lot of but never used. So I decided to plunge into it to see how rich the solution was. Since I only use CI for Terraform deployments, I aimed to cover the features, not the dev part.
This post is rather a long-mixed pack of titbits & notes out of my 2 weeks’ immersion, highlighting the particularities and features of GitHub Actions in the CI/CD landscape, with no specific order. This will hopefully get you started with GitHub Actions, whether you’re familiar with CI or just a curious newcomer.
Table of Contents
As most of you know, GitHub Actions is a platform that allows developers to automate workflows and tasks directly within GitHub repositories. Below is a brief description of key components of GitHub Actions:
Workflows: Configurable, automated process that executes one or more actions and is defined by YAML files checked into the repository under .github/workflows
Runner: a GitHub or self-hosted VM used to run your workflow with a list of tools preinstalled
Triggers: Workflows can be triggered by specific events, such as push, and pull requests, or scheduled times
Actions: Are prebuilt tasks written in multiple languages that can be called in a workflow
Marketplace: Where developers can discover, and use actions and workflows created by the community
Secrets: Allow Devs to store and use sensitive information (credentials) securely in their workflows
Integration: Integrates with numerous tools and services, to streamline dev & deployment workflows
GitHub Plans: Personal (GitHub Free or GitHub Pro), Organizations (GitHub Team, GitHub Enterprise)
Ok, time to unveil the coffers of valuable git bits, curated from 35+ tabs of doc during my 2 weeks immersion.
Buckle up!
GitHub Actions has a variety of default runners with 3 OS allowing you to run your workflows on different platforms
Runners are VMs that come with preinstalled software that allows you to run any app or code in your pipeline
Bash, Node.js, Perl, Python, Ruby, Swift, Dash, C++, Julia, Kotlin, Mono, MSBuild
Pip/pip3, Cpan, Helm, Yarn, Homebrew, Miniconda, Npm, NuGet, Pipx, RubyGems, Vcpkg
Git, SVN, Ansible, Packer, Terraform, Pulumi, Kubectl, Minikube, R, Heroku, Docker, Apt-fast, AzCopy
AWS CLI, Azure CLI, GitHub CLI, Google Cloud SDK, Alibaba Cloud CLI, Hub CLI, OpenShift CLI, ORAS CLI, Vercel CLI
Other
JAVA, .NET Tools, Cached tools (Go, Node.js, Python, Pypy, Ruby), Cached Docker Images
PHP Tools, Haskell Tools, Rust Tools, PowerShell Tools, and modules
Browsers: Google Chrome, chromium, Microsoft Edge, Mozilla Firefox, Solenium Server
Databases: sqllite, MySQL, PostreSQL, MSSQL tools (sqlcmd, SQL package)
WebServers: Nginx, Apache2
Mobile OS: Android Command Line Tools, Android Emulator, Android SDK platforms, Google Play services, Google repo
The basic structure of a GitHub Actions workflow consists of triggers, jobs, workflow syntax, and commands.
Triggers define the events that can trigger a workflow, such as pushes to the repository or pull requests
Jobs define the individual tasks or steps that need to be executed as part of the workflow
Example
Name: Workflow Name
on: Events that trigger a workflow (push on the branch git_actions for any change in the paths section)
env: Variables definition (hardcoded or imported from the environment such as secrets, vars)
Permissions: To allow your actions to use the token_id
Jobs section:
JobName, runner OS (runs-on), environment, default shell, and working directory
Steps section: checkout your code repo + other steps(run tests, build artifacts..)
Same for the next job…
As shown below, these prebuilt tasks can be easily called in a workflow and are written in multiple languages. But public actions can’t be referenced from self-hosted runners. They are publicly stored in GitHub Market place.
# example: “setup-node” action that downloads node.js and add it to the PATH
steps: ... - uses: actions/setup-node@v3 with: node-version: 18
Public GitHub actions can also be risky to your security and privacy. For instance, malicious actions could steal your secrets, modify your code, or compromise your server. Even if the actions are not malicious, they could have vulnerabilities, or outdated dependencies that could affect your project.
Read more in this stackoverflow thread
Personally, I don’t have time to check random people’s code for backdoors, so I only use actions from trusted sources, like official authentication actions from major cloud platforms and those made by GitHub.
Beware: GitHub Actions logs of your public repo are visible to anyone as opposed to private ones
Features like Environments, environment secrets, and environment protection rules are available in public repositories for all GitHub plans (Free, Pro, Team, Enterprise)
For access to environments, environment secrets, and deployment branches in private or internal. repositories, you must use GitHub Pro, Team, or GitHub Enterprise
Actions and reusable workflows stored in private repositories cannot be used in public repositories
GitHub doesn’t allow individual accounts to use self-hosted runners on public repositories
You can share actions and reusable workflows from your private repo without making them public, by allowing GitHub workflows to access a private repository that contains the action or reusable workflow
The environment is an abstraction allowing differentiate deployments(dev, prod, staging), preventing unauthorized deployments, preserving secrets, tracking changes, and much more
You can use environment protection rules to require manual approval, delay a job, or restrict the environment to certain branches (i.e. dev, staging, dev).
It’s Available for all public repositories and private repositories for Pro, Team, and Enterprise accounts
Referencing environment in Git actions has 3 scopes:
The entire workflow, by using env at the top level of the workflow file.
The contents of a job within a workflow, by using jobs.<job_id>.env.
A specific step within a job, by using jobs.<job_id>.steps[*].env.
You can share custom environment variable with any subsequent steps in a workflow job by defining or updating the environment variable and writing this to the GITHUB_ENV
environment file.
echo
"{environment_variable_name}={value}" >> "$GITHUB_ENV"
For sharing environment between jobs or
between workflows you will need GITHUB_OUTPUT
You can have a repository, environment, as well as intra-workflow (job, step) variable level
Context is a collection of variables describing workflow runs, runner environments, jobs, steps, secrets & much more. The context reference syntax is ${{ context.variable }}
github
reference information about the workflow run & events that triggered the run. i.e github.repository
env
Reference environment variable defined in the workflow.i.e ${{ env.MY_VARIABLE }}
vars
context to access configuration variable values ${{ vars.MY_VAR }}
There’s a similar collection of variables called default variables within a runner (i.e. GITHUB_RUN_ID)
If you want to see all the information that GitHub Actions has in context, use the handy toJson
function
Runner env variables are always interpolated on the runner VM. However, parts of a workflow are processed by GitHub Actions and are not sent to the runner
In GitHub Actions, secrets are used to store sensitive information like passwords, API keys, tokens, etc.
There are organization, repository, and environment-level secrets.
In case of conflict, the organization is overridden by the repository, and the repository is overridden by env values.
Secret names can’t contain spaces, are not case-sensitive, & must be unique within the same level.
Secret names must not begin with the prefix GITHUB_.
secrets.GITHUB_TOKEN is a temporary token for each workflow run.
Exploitability and impact of untrusted input are real, read more in this excellent GitHub Securitylab post
How safe is it on public repos and forks?
Secrets are safe to use in public repositories as they are automatically masked in build logs & show as *
But If in your workflow you create a credential from a secret (e.g. base64 an API key) then you should mask the new value so it doesn’t leak in the build log.
With the exception of GITHUB_TOKEN, secrets are not passed to the runner when a workflow is triggered from a forked repository.
Secrets are not automatically passed to reusable workflows.
If you have a public repository, make sure all outside collaborators’ PR requires approval.
Public repository pull_request
events triggered by forks do not have access to secrets, except for the default GITHUB_TOKEN
. Additionally, The GITHUB_TOKEN
has read-only access when an event is triggered by a forked repository. This default setup prevents an attacker from creating a PR containing a workflow that captures secrets or uses secrets to perform operations.
What is a mask and is it really useful?
You can mask, or hide, any sensitive data in GitHub Actions logs by adding a new step add-mask in a Workflow.
Unfortunately, a variable will still be visible at least once before a mask is applied to it, and from then that value cannot be passed between runners. More examples here
needs context: contains outputs from all jobs that are defined as a direct dependency of the current job
By default, all your jobs run in parallel in a workflow, but you often need them to run sequentially
Other needs variables
need.<job_id>: A single job that the current job depends on
needs.<job_id>.outputs: outputs of a job that the current job depends on
needs.<job_id>.result: The result of a job that the current job depends on. Possible values are success, failure, canceled, or skipped
Artifacts:
Allow you to share data between running jobs and save them after the workflow is complete
An artifact is a file or collection of files produced during a workflow run
The Differences
Artifacts are used to save files after the workflow ended. (handy for Logs, manifest, state file, config file, Tests Results, Reports, etc)
Caching is used to re-use data/files between jobs or workflows (i.e sharing build dependencies files that don’t change often between jobs)
Beware: Both artifacts and Caches are accessible to anyone in public repositories. An artifact can be downloaded, the cache can be reused
The default behavior of environment protection rules is to set manual approval for first-time contributors
In that case, an attacker could create a simple and innocent pull request (like a documentation update)
When accepted, his subsequent pull request could be malicious and automatically trigger the workflow
So you need to set “Require approval for all outside collaborators” to ensure a more robust defense
Private Manual Approval: use the below action if you don’t have an Enterprise/Pro account but still want manual approval without the use of environments
Step ID vs step name:
ID is used as a reference, from other jobs or steps (i.e., in jobs. <job_id>. needs)
The name is used for display purposes on GitHub
How to run commands without specifying a step name: run: echo “Run my shell command “
Why install custom software via actions vs use local one in the runner (example setup-terraform):
Terraform_setup action downloads the right version for you to ensure that updates to your infrastructure are safe and predictable (required_version).
The local version of Terraform might be too new for the required version and will fail Terraform init
That’s it, a long but very useful cheat sheet that helped me and hopefully helps you explore GH Actions
Again if your workflow is in a public repo, remember below safety measures
Don’t have any workflow with a pull_request
trigger and never plan to make one.
Have the “Require approval for all outside collaborators” option for GitHub Actions turned on.
You must only invite trustworthy outside collaborators.
Next, I will write a series about Multicloud terraform deployments in GitHub actions
Blabla Free Post: These are just some of my (personal) top Oracle CloudWorld 20232 sessions I will have the chance to attend and speak at this ... Read More
Introduction In my previous blog post, we explored the challenges of relying on terraform registry modules for code sanity checks. Additionally, we ... Read More