Modern software development workflows have increasingly migrated toward continuous integration and continuous deployment (CI/CD) pipelines hosted on platforms like GitHub Actions. A significant architectural challenge arises when these pipelines need to interact with code that is not publicly accessible. Projects often require dependencies, custom actions, or reusable workflows stored in private repositories. Historically, enabling this cross-repository communication required manual generation of deploy keys or Personal Access Tokens (PATs), a process that introduced complexity regarding key rotation, scope management, and security hygiene. The current ecosystem offers more robust, granular, and automated mechanisms for securing these interactions, ranging from SSH key configurations to GitHub Apps and native repository permission settings.
Historical Context and Authentication Challenges
Before the advent of sophisticated workflow permission models, consuming private projects within GitHub Actions was a manual endeavor. Development teams were forced to generate deploy keys or Personal Access Tokens (PATs) to authenticate requests from their CI/CD runners to other private repositories. This approach, while functional, introduced significant administrative overhead. PATs required careful management to ensure they did not expire unexpectedly during long-running builds, and deploy keys needed to be distributed and rotated securely across different environment variables. The primary goal of modern solutions is to eliminate these manual touchpoints while maintaining strict security boundaries, ensuring that sensitive code remains inaccessible to unauthorized workflows.
Native Repository Access Permissions
GitHub has integrated native controls that allow repository owners to define precisely which external workflows can access their code. This feature is particularly relevant for organizations that wish to share actions or reusable workflows within a trusted circle without exposing them to the public. Configuring these permissions requires navigating the repository settings interface.
On GitHub, navigate to the main page of the private repository. Under your repository name, click Settings. In the left sidebar, click Actions, then click General. Under the Access section, administrators can choose from specific access settings that dictate the scope of availability.
- Not accessible - Workflows in other repositories cannot access this repository.
- Accessible from repositories owned by 'USER NAME' user - Workflows in other repositories that are owned by the same user can access the actions and reusable workflows in this repository. Access is allowed only from private repositories.
- Accessible from repositories in the 'ORGANIZATION NAME' organization - Workflows in other repositories that are part of the 'ORGANIZATION NAME' organization can access the actions and reusable workflows in this repository.
After selecting the appropriate scope, the user must click Save to apply the settings. These native permissions provide a declarative approach to access control, removing the need for external credential management for internal organizational flows. For environments requiring programmatic management, the REST API can be used to set or get details of the level of access, offering DevOps teams the ability to automate permission policies across large repository fleets.
Leveraging Third-Party Actions for Private Checkouts
For scenarios where native permissions are insufficient—such as when accessing repositories outside the same organization or user scope—third-party actions like daspn/private-actions-checkout provide a powerful alternative. This action simplifies the use of custom private actions and promotes code reuse by iterating through a list of repositories and checking them out into the job's workspace. It supports authentication via GitHub Apps or multiple SSH keys and optionally configures git to allow subsequent steps to provide authenticated access to private repos.
The action is tested on ubuntu-latest and macos-latest, with no Windows support currently available. To utilize this tool, a workflow file must be created in the repository's .github/workflows directory. The core mechanism involves providing a supported authentication method accepted by the Git protocol.
Configuration and Parameters
The private-actions-checkout action relies on specific inputs to function correctly. Understanding these parameters is critical for successful implementation.
actions_list- OPTIONAL: List of private actions to checkout. Must be a JSON array and each entry must match the format owner/repo@ref. May be an empty array if no actions are required.checkout_base_path- OPTIONAL: Where to checkout the custom actions.ssh_private_key- The SSH private key to use for authentication.app_id- The GitHub App ID for authentication.app_private_key- The private key for the GitHub App.configure_git- A boolean flag to configure git for subsequent steps.
Authentication Strategies: SSH Keys
One of the most common methods for authenticating private checkouts is the use of SSH keys. The action supports both single and multiple SSH keys, allowing for granular access control across different repository owners.
In a single SSH key scenario, the workflow defines the list of actions and the base path for checkout. The private key is referenced from the repository's secrets.
yaml
name: 'No SSH Key example workflow'
on: push
jobs:
example:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
# setting up the SSH agent using a third party action
- uses: webfactory/[email protected]
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
# as no SSH key is provided the action will assume valid SSH credentials are available
- name: Private actions checkout
uses: daspn/private-actions-checkout@v2
with:
actions_list: '["githubuser/my-private-action-1@v1", "githubuser/my-private-action-2@v1"]'
checkout_base_path: ./.github/actions
- name: Validation
run: |
ls -lR ./.github/actions
# the custom private action will be available on the job's workspace
- name: 'Using custom private action 1'
uses: ./.github/actions/my-private-action-1
with:
some_arg: test
- name: 'Using custom private action 2'
uses: ./.github/actions/my-private-action-2
For more complex environments where dependencies reside in repositories owned by different users or organizations, multiple SSH keys can be employed. This requires separate steps for each distinct key, ensuring that the correct credentials are used for the corresponding repositories.
yaml
name: 'Multiple SSH Keys workflow example'
on: push
jobs:
example:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Checking out private actions from github_user
uses: daspn/private-actions-checkout@v2
with:
actions_list: '["github_user/my-private-action-1@v1", "github_user/my-private-action-2@v1"]'
checkout_base_path: ./.github/actions
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY_1 }}
- name: Checking out private actions from another_github_user
uses: daspn/private-actions-checkout@v2
with:
actions_list: '["another_github_user/my-private-action-3@v1", "another_github_user/my-private-action-4@v1"]'
checkout_base_path: ./.github/actions
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY_2 }}
- name: Validation
run: |
ls -lR ./.github/actions
# the custom private action will be available on the job's workspace
- name: 'Using custom private action 1'
uses: ./.github/actions/my-private-action-1
with:
some_arg: test
- name: 'Using custom private action 4'
uses: ./.github/actions/my-private-action-4
Authentication Strategies: GitHub Apps
For enterprise environments, the recommended approach is to use a GitHub App per organization with a single installation. This method eliminates the need for a "machine account" (a dummy user account often used for service accounts) and leverages the more secure and granular permissions model provided by GitHub Apps.
When using a GitHub App to authorize a Go application to fetch other private dependencies, the workflow utilizes the app_id and app_private_key secrets. The configure_git option is set to true to ensure that subsequent steps, such as go build, can access the private repositories authorized to the app.
yaml
name: 'Example workflow'
on: push
jobs:
example:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Private actions checkout
uses: daspn/private-actions-checkout@v2
with:
app_id: ${{ secrets.APP_ID }}
app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
configure_git: true
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.15
# Go build will be able to access other private repos authorized to the app
- name: Build
run: go build -v .
Development and Maintenance of Private Actions
Creating and maintaining custom private actions requires specific development tools and processes. The private-actions-checkout action itself, and actions developed using similar patterns, often require Node.js for the build process. Specifically, Node.js 12.x is required to build the code.
After installing Node.js 12.x, developers must install the NPM package zeit/ncc by running the following command:
bash
npm i -g @zeit/ncc
npm i
npm run build
This build process updates the dist/index.js and dist/cleanup/index.js files, ensuring that the action is properly bundled and optimized for execution within the GitHub Actions runner environment. It is important to note that while these third-party solutions are powerful, actions like Private Actions Checkout are not certified by GitHub. Users should weigh the benefits of functionality against the implications of using non-certified tools in their security-critical pipelines.
Usage Limits and Considerations for Private Repositories
While the technical mechanisms for accessing private repositories are robust, operational constraints remain. Using GitHub Actions on a private repository functions similarly to public repositories in terms of workflow execution, but there are distinct limitations. Specifically, there is a limit on the number of free minutes per month available for private repositories, and there are limits on storage for artifacts. Teams must monitor their usage to ensure they remain within these bounds or upgrade to a plan that accommodates their CI/CD volume.
Despite these limitations, the ability to test actions and workflows in a private repository before deploying them to public or production repositories is a valuable practice. Many developers use private repositories as sandbox environments to validate their CI/CD logic, ensuring that sensitive code and proprietary algorithms are not exposed during the experimental phase of development.
Conclusion
The evolution of GitHub Actions has transformed how developers manage private code dependencies. The shift from manual PAT and deploy key management to native repository permissions and automated GitHub App authentication represents a significant leap in both security and operational efficiency. By leveraging tools like daspn/private-actions-checkout and configuring appropriate access settings, organizations can maintain strict control over their intellectual property while still benefiting from the modularity and reuse that private actions provide. Whether through SSH keys for specific user scopes or GitHub Apps for enterprise-wide integration, the modern developer has a comprehensive toolkit for orchestrating secure, private workflows. As the ecosystem continues to mature, the emphasis remains on reducing manual overhead while increasing the granularity and auditability of access controls.