Build Centralized Security Workflows in Github: A tale of Reusable Workflows
This blog walks you through how you can leverage github’s reusable workflows to create a centralised github repository for all your github security workflows for better maintainability and secret management .

What are reusable workflows?
Reusable workflows are pre-defined workflow files, that can be called from another workflow file. The advantage of this feature is that in an organization you can create a centralized repository for your workflow files and then call these workflows from other repository.
What Problem does it solve?
- The need to configure secrets for every Repository
- Offers better maintainability by managing all the workflow in a centralized repository.
- Allows us to create a single workflow file that can call multiple github workflows .
How does it solve the above problems?
- Reusable workflows offers the concept of inheriting secrets from the parent repository, which allows any caller workflow to use the secrets configured in the repository of the callable workflow file.
- Maintainability means that, let's say you need to make version changes to the action you're using in your workflow file, and now this workflow file is used across multiple repos. Now you have to individually go through each repo and make the changes. This can be circumambulated with the help of callable workflows, where the changes are only needed to be made in the callable workflow file and all the caller's workflows would have the changes reflected.
- One caller workflow can use multiple called workflows. Each called workflow is referenced in a single line. The result is that the caller workflow file may contain just a few lines of YAML, but may perform a large number of tasks when it’s run. When you reuse a workflow, the entire called workflow is used, just as if it was part of the caller workflow.
Let's see how we can use reusable workflows to manage centralized security workflow repository and create a comprehensive callable workflow file that uses these security workflows.
Pre-Requsite
- Create a GitHub organization
- Create a repo under the organization called Security-Workflows ( some-convenient name ) .
- Create a directory under the created repo with this structure .github/workflows/
- Go to repo setting under Action> General enable the following permissions


Creating callable workflows
A workflow can be converted into a callable workflow when we add the following event trigger .
on:
workflow_call
Lets assume this workflow is under the following path :
Security-360/Security-Workflows/.github/workflows/callable.yml
Then we can use this particular workflow in any other repo by creating a caller workflow with the uses tag pointing to the location of the caller workflow.
on:
push:
branches:
- main
jobs:
Security-Workflow:
uses: Security-360/Security-Workflows/.github/workflows/callable.yml@main
Note: @main at the end of the path points to the branch from which the workflow should be accessed. It can be compared with the version tag of a normal action .
Creating Security Workflows
Let's create two workflow files that help us to perform the following
- Scan code for vulnerabilities
- Keep track of the Dependabot alerts in a repo and alert us when new alerts pop up for the week.
We will be using the following actions to acheive the above requirements
- Semgrep Cli action
- Dependapager ( A custom action i created:) )
Semgrep CLI Action
Semgrep is a fast, open-source, static analysis engine for finding bugs, detecting vulnerabilities in third-party dependencies, and enforcing code standards.
Below is the callable workflow file to run semigrep cli on your repo code. Let's call it semgrep.yml and add it to the Security-Workflows repository under the .github/workflows/ path.
name: Semgrep
on:
workflow_call:
jobs:
semgrep:
name: Scan
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
if: (github.actor != 'dependabot[bot]')
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Run SemGrep
continue-on-error: true
run: semgrep ci --config auto
Dependapager Action
A github action that helps to send your Dependabot Alerts to Slack and create JIRA Tickets for Critical and High issues.
You can refer more about it here: https://github.com/marketplace/actions/dependapager
Let's create a callable workflow as we did for the semgrep action under the same path and name it dependapager.yml
on:
workflow_call:
jobs:
send-slack-alerts:
runs-on: ubuntu-latest
steps:
- name: Dependapager
id: pager
uses: pwned-17/dependapager@v1.6
with:
github_personal_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
slack_token: ${{ secrets.SLACK_TOKEN }}
channel: CHWEXXXX
jira_token: ${{ secrets.JIRA_API_TOKEN }}
jira_url: 'https://xxxx.atlassian.net'
jira_useremail: 'user@xxx.com'
jira_project_key: 'KEY'
jira_issue_type: 'Task'
- name: Check Ouptuts
run: |
echo ${{ steps.pager.outputs.total_alerts }}
- name: Check Events
run: |
echo ${{ github.event_name }}
The following action requires the following inputs and secrets to be configured
github_personal_token:
description: " Github Personal Token to Query github for dependabot alerts"
required: true
slack_token:
description: " Slack Bot Token to Send Alerts "
required: true
channel:
description: " Slack Channel to Send the Alerts Too"
required: true
jira_token:
description: " Token Required for quering JIRA REST API"
required: true
jira_url:
description: " Your Organizations Jira Cloud URL"
required: true
jira_useremail:
description: " Email id of the user associated with the token"
required: true
jira_project_key:
description: " The Project Key for which Jira Tickets are created "
required: true
jira_issue_type:
description: " Issue Type As Task or Epic or INC"
required: true
Add the following secrets to the repo secrets
Refer : Creating Repo Secrets
- PERSONAL_ACCESS_TOKEN (github personal access token )
- SLACK_TOKEN (Slack Bot Token )
- JIRA_API_TOKEN (JIRA API token to create Jira issues)
Once you have set up the above repository and created these workflow files under them, now you are ready to use this workflow across any repository in your organization . Lets see how you can create a caller workflow for the above two workflows .
Caller Workflow
Below is a workflow file called security-workflows.yml that calls the two workflows that we have written in the Security-Workflow repository .
name: Security Workflows
on:
schedule:
- cron: "0 0 * * TUE"
pull_request:
branches:
- main
- develop
- master
push:
branches:
- main
- develop
workflow_dispatch:
jobs:
Dependapager:
if: ${{ github.event_name == 'schedule' }}
uses: Security-360/Security-Workflows/.github/workflows/dependapager.yml@main
secrets: inherit
Sem-Grep:
if: ${{ github.event_name == 'pull_request' }} or ${{ github.event_name == 'push' }}
uses: Security-360/Security-Workflows/.github/workflows/semgrep.yml@main
The above workflow file is called a caller workflow file, as we can see this particular workflow calls the two workflows that we have written in the Security-Workflows repository.
This workflow file can be added to any GitHub repository having workflows configured under the same organization.
Let's understand a bit about this caller workflow.
- The caller workflow has the following event triggers
- push → Trigger this workflow for every push in the repo
- schedule →Run this workflow on a given cron time
- pull_request →Run this workflow for every pull request - It has two jobs
- Dependapager → That uses dependapager.yml workflow
- Sem-Grep → That uses semgrep.yml workflow - It has an if condition that
- Checks if the event that triggered is scheduled then runs dependapager
- Check if the event is push or pull run semgrep - It has a weird secret: inherit tag
- This tag tells the workflow to use the secrets of the repo for which we have configured in the callable workflow

Whenever an event that matches the event fields in the above workflow file , github runs this workflow file for that repository . The caller workflow based on the event ,calls the callable workflow file sitatued in the security-worklfows repository . Secrets are also inherited in this case from the repository of the callable workflow , due to the prcense of secrets:inherit flag .