# Create an Assumable Identity for a GitHub Actions Workflow

URL: https://deploy-preview-3616--ornate-narwhal-088216.netlify.app/platform/administration/assumable-ids/identity-examples/github-identity.md
Last Modified: July 21, 2026
Tags: Chainguard Containers

Tutorial outlining how to create a Chainguard identity that can be assumed by a GitHub Actions workflow.

Chainguard&rsquo;s assumable identities are identities that can be assumed by external applications or workflows in order to perform certain tasks that would otherwise have to be done by a human. For instance, an assumable identity can be used to allow a GitHub Actions workflow to pull images from cgr.dev without a static pull token.
This tutorial outlines how to create an identity, and then create a GitHub Actions workflow that will assume the identity to interact with Chainguard resources.
Prerequisites To complete this guide, you will need the following.
One of: chainctl — the Chainguard command line interface tool — installed on your local machine. Follow our guide on How to Install chainctl to set this up. terraform installed on your local machine. Terraform is an Infrastructure as Code tool which this guide will use to create various cloud resources. Follow the official Terraform documentation for instructions on installing the tool. A GitHub repository you can use for testing out GitHub identity federation. To complete this guide, you must have permissions to create GitHub Actions on this testing repo. Creating an Identity Note: GitHub issues OIDC tokens whose sub claim embeds immutable numeric IDs for the repository owner and the repository. For example, the subject repo:my-org@123456/repo-name@654321:ref:refs/heads/main replaces the older name-only form repo:my-org/repo-name:ref:refs/heads/main. This format is the default for repositories created after July 15, 2026, and is available as an opt-in for older repositories through GitHub&rsquo;s OIDC settings.
An identity that matches the older name-only subject will not match a token that carries the immutable subject, so the workflow fails to authenticate. The examples that follow use the immutable format. If your repository still sends the name-only subject, leave out the @&lt;owner-id&gt; and @&lt;repo-id&gt; portions.
Finding your repository&rsquo;s numeric identifiers The immutable subject claim uses the numeric ID of the repository owner and the numeric ID of the repository.
To retrieve the subject claim in the GitHub UI, modify and browse to this URL:
https://github.com/&lt;org-name&gt;/&lt;repo-name&gt;/settings/actions/oidc-configurationTo retrieve the subject claim with the GitHub CLI:
gh api repos/OWNER/REPO --jq &#39;{owner_id: .owner.id, repo_id: .id}&#39;You can also preview the exact subject your repository sends from its OIDC settings in the GitHub web interface. To confirm the subject a running workflow presents, inspect the sub claim of the OIDC token in the workflow logs. For background on the format, see GitHub&rsquo;s changelog announcing immutable subject claims for GitHub Actions OIDC tokens.
Chainctl This command creates an identity that can be assumed by workflows in the my-org/repo-name repository. Substitute the owner and repository IDs you retrieved earlier. The identity is bound to the registry.pull role.
chainctl iam identities create github my-identity-name \ --github-repo=my-org@&lt;owner-id&gt;/repo-name@&lt;repo-id&gt; \ --role registry.pullYou can also include the --github-ref flag to restrict it to workflows that run from a specific branch. For instance, the main branch.
chainctl iam identities create github my-identity-name \ --github-repo=my-org@&lt;owner-id&gt;/repo-name@&lt;repo-id&gt; \ --github-ref=refs/heads/main \ --role registry.pullRegex is also available. For example, you can create an identity that can be assumed by multiple repositories and multiple branches. Because every repository in an organization shares the same owner ID, a single pattern can match all of them.
chainctl iam identities create github my-identity-name \ --github-repo=&#39;my-org@&lt;owner-id&gt;/.*&#39; \ --github-ref=&#39;refs/heads/main|master&#39; \ --role registry.pullThis will return the identity&rsquo;s UIDP (unique identity path). Note this value down, as you&rsquo;ll need it to set up the GitHub Actions workflow.
If you need to retrieve the UIDP later on, you can always run the following chainctl command to list the identity.
chainctl iam identities list --name=my-identity-name Terraform Alternatively, you could create the identity with the Chainguard Terraform provider.
Substitute your Chainguard organization name, GitHub organization, and GitHub repository for &lt;org-name&gt;, &lt;github-org&gt;, and &lt;github-repo&gt;, respectively. Substitute the numeric owner and repository IDs for &lt;owner-id&gt; and &lt;repo-id&gt;, following the steps in Finding your repository&rsquo;s numeric identifiers.
data &#34;chainguard_group&#34; &#34;org&#34; { name = &#34;&lt;org-name&gt;&#34; } resource &#34;chainguard_identity&#34; &#34;my_identity_name&#34; { parent_id = data.chainguard_group.org.id name = &#34;my-identity-name&#34; claim_match { issuer = &#34;https://token.actions.githubusercontent.com&#34; subject = &#34;repo:&lt;github-org&gt;@&lt;owner-id&gt;/&lt;github-repo&gt;@&lt;repo-id&gt;:ref:refs/heads/main&#34; } } data &#34;chainguard_role&#34; &#34;registry_pull&#34; { name = &#34;registry.pull&#34; } resource &#34;chainguard_rolebinding&#34; &#34;my_identity_name_registry_pull&#34; { identity = chainguard_identity.my_identity_name.id group = data.chainguard_group.org.id role = data.chainguard_role.registry_pull.items[0].id } output &#34;my_identity_name_id&#34; { value = chainguard_identity.my_identity_name.id }In this example the chainguard_identity.my_identity_name resource defines an identity in your organization that can be assumed by a GitHub workflow that matches the claims in the claim_match block.
The chainguard_rolebinding.my_identity_name_registry_pull resource binds the registry.pull role to the identity.
The my_identity_name_id output provides the identity&rsquo;s UIDP (unique identity path). You&rsquo;ll need this value to set up the GitHub Actions workflow.
Creating and Testing a GitHub Actions Workflow This example workflow definition assumes an identity with the setup-chainctl GitHub Action, lists repositories with chainctl and pulls an image from cgr.dev.
Commit this workflow to the main branch of your repository as .github/workflows/assume-and-explore.yaml, substituting &lt;identity-id&gt; with the UIDP of the assumable identity you created in the previous step and &lt;org-name&gt; with the name of your Chainguard organization.
name: Assume and Explore on: workflow_dispatch: {} jobs: assume-and-explore: name: actions assume example permissions: id-token: write runs-on: ubuntu-latest steps: - uses: chainguard-dev/setup-chainctl@main with: identity: &lt;identity-id&gt; - run: | chainctl image repo list --parent=&lt;org-name&gt; - run: | docker pull cgr.dev/&lt;org-name&gt;/example-image:latestOnce its committed, you can trigger the workflow by navigating to Actions &gt; Assume And Explore from the home page of your repository and selecting Run workflow.
Learn more For more information about how assumable identities work in Chainguard, check out our conceptual overview of assumable identities. Additionally, the Terraform documentation includes a section on recommended best practices which you can refer to if you&rsquo;d like to build on the provided Terraform configuration for a production environment. Likewise, for more information on using GitHub Actions, we encourage you to check out the official documentation on the subject.

