Skip to content

Permissionizer

GitHub App

Permissionizer

GitHub App

Permissionizer is a GitHub App that helps writing cross-repository GitHub Actions workflows by issuing short-lived, policy-based tokens as an alternative to individual Personal Access Tokens (PATs) or custom GitHub apps with broad permissions.

With Permissionizer you can easily define a policy to allow other repositories to request scoped tokens with only the permissions required. For example, you can allow a foo-service repository to update the manifests in the foo-service-manifests repository:

# Permissionizer policy in `my-org/foo-service-manifests` repository
self: my-org/foo-service-manifests
allow:
  - repository: my-org/foo-service
    permissions:
      contents: write

The foo-service repository can then request a token with contents: write permission to update the manifests:

# Workflow in `my-org/foo-service` repository
name: Update deployment manifests
on:
  tag: v*

permissions:
  id-token: write # Required to verify the repository identity

jobs:
  update-deployment-manifests:
    runs-on: ubuntu-latest
    steps:
      - name: Request token from Permissionizer
        id: request-token
        uses: permissionizer/request-token@v1
        with:
          target-repository: my-org/foo-service-manifests
          permissions: |
            contents: write

      - name: Checkout manifests repository
        uses: actions/checkout@v5
        with:
          repository: my-org/foo-service-manifests
          token: ${{ steps.request-token.outputs.token }}
          ref: main

      - name: Update deployment manifests for version ${{ github.ref }}
        run: |
          ... update manifests logic here ...

          git commit -am "Update manifests for $GITHUB_REF"
          git push origin main

How does it work?

Permissionizer App acts as an OIDC provider between GitHub repositories. While Permissionizer App itself has broad permissions to your repository (or an organization), it only issues short-lived tokens with the permissions explicitly allowed by a policy defined in the target repository.

When a workflow in a repository (e.g. foo-service) wants to access another repository (e.g. foo-service-manifests), it uses the permissionizer/request-token action to request a token from the Permissionizer Server (available for free as cloud version and for self-hosting). The action provides an ID token (requires id-token: write permission) that proves the identity of the requesting repository. The server verifies the ID token and checks the policy in the target repository to see if the requesting repository is allowed to request a token with the specified permissions. If the request is allowed, a short-lived token with the requested permissions is issued, which can then be used to access the target repository.

Why not use PATs or custom GitHub Apps?

The only way to access another repository in GitHub Actions is to use a Personal Access Token (PAT) or a GitHub App. The problem with those is that they are usually long-lived and often have broad permissions. Such tokens (or app private keys) need to be shared across all repositories, which poses a security risk. If a token is compromised, an attacker can gain access to all repositories that the token has access to.

Even if handled correctly, managing multiple PATs or GitHub Apps using different sets of permissions and installations to required repositories becomes difficult to manage. With Permissionizer, there is only a single GitHub App to manage, and the permissions are scoped by explicitly declaring access policies in every repository that should be given access to.

Zero Trust Policy

Tokens can only be issued if explicitly allowed by the target repository's policy, ensuring strict access control. The identity of the workflow in the requesting repository as well as the allowed access policy is verified by the Permissionizer Server. This process is seamlessly managed by thepermissionizer/request-token@v1 action.

Permissioniezr access policy is defined in a .github/permissionizer.yaml file in the target repository and has wide flexibility to define which repositories are allowed to request tokens and with which permissions. The policy can also restrict token requests to specific branches or workflows in the requesting repository.

self: my-org/foo-service-manifests
allow:
  # (required)
  # Repository requesting the token
  - repository: my-org/foo-service
    # (required)
    # Permissions that can be requested by `permissionizer/server`
    # Only permissions listed here are allowed to be requested
    # Requester can always request a subset of the allowed permissions or lower access
    # (i.e. requesting only `issues: read` when allowed `contents: write`, `issues: write`)
    # see all available permissions
    # https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#repository-permissions
    permissions:
      contents: write
      secrets: read
    # (optional)
    # Restricts requesting token to specific branches (refs) of the requesting repository
    # Accepts short and full formats of `ref` (e.g. `main`. `refs/heads/main`, `refs/tags/v1.0.0`, `refs/tags/v*`)
    ref: main
    # (optional)
    # Restricts requesting token only from a specific workflow of the requesting repository
    # Also allows specifying a ref to a shared workflow, e.g. my-org/reusable-workflows/.github/workflows/release.yaml@refs/heads/main
    workflow_ref: .github/workflows/release.yaml

Following this policy, only the my-org/foo-service repository is allowed to request a token with access to the my-org/foo-service-manifests repository. The issued token will have contents: read, secrets: write, and a default metadata: read permissions.

In the example above, to harden the security, the policy requires the requesting workflow to run from the main branch. Additionally, it restricts requesting the token to the release.yaml workflow only, so that the token cannot be issued from any other workflow within my-org/foo-servicer and not from other branches or pull requests.

Developer

Permissionizer is provided by a third-party and is governed by separate terms of service, privacy policy, and support documentation.

Report abuse