Skip to content

Commit a16f7ba

Browse files
committed
build(release): 1.0.0 [skip ci]
1 parent 9ccc6db commit a16f7ba

17 files changed

+32491
-12301
lines changed

.github/workflows/release.yml

+10-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ permissions:
99
contents: write
1010
issues: write
1111
pull-requests: write
12+
id-token: write
1213

1314
jobs:
1415
release:
@@ -20,6 +21,13 @@ jobs:
2021
with:
2122
persist-credentials: false
2223

24+
- name: AWS Login
25+
uses: aws-actions/configure-aws-credentials@v4
26+
with:
27+
aws-region: eu-west-1
28+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
29+
role-session-name: release-create-github-app-token-aws
30+
2331
- uses: actions/setup-node@v4
2432
with:
2533
node-version-file: .node-version
@@ -30,8 +38,8 @@ jobs:
3038
- uses: ./
3139
id: app-token
3240
with:
33-
app-id: ${{ vars.RELEASER_APP_ID }}
34-
private-key: ${{ secrets.RELEASER_APP_PRIVATE_KEY }}
41+
app-id: ${{ secrets.APP_ID }}
42+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
3543
# install release dependencies and release
3644
- run: npm install --no-save @semantic-release/git semantic-release-plugin-github-breaking-version-tag
3745
- run: npx semantic-release --debug

.github/workflows/test.yml

+15-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@ on:
44
push:
55
branches:
66
- main
7+
- dev
78
pull_request:
89
workflow_dispatch:
910

11+
permissions:
12+
contents: read
13+
id-token: write
14+
1015
concurrency:
1116
group: ${{ github.workflow }}-${{ github.ref }}
1217
cancel-in-progress: true
@@ -33,6 +38,14 @@ jobs:
3338
if: github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login
3439
steps:
3540
- uses: actions/checkout@v4
41+
42+
- name: AWS Login
43+
uses: aws-actions/configure-aws-credentials@v4
44+
with:
45+
aws-region: ${{ vars.AWS_REGION }}
46+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
47+
role-session-name: test-create-github-app-token-aws
48+
3649
- uses: actions/setup-node@v4
3750
with:
3851
node-version: 20
@@ -42,8 +55,8 @@ jobs:
4255
- uses: ./ # Uses the action in the root directory
4356
id: test
4457
with:
45-
app-id: ${{ vars.TEST_APP_ID }}
46-
private-key: ${{ secrets.TEST_APP_PRIVATE_KEY }}
58+
app-id: ${{ secrets.APP_ID }}
59+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
4760
- uses: octokit/[email protected]
4861
id: get-repository
4962
env:

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.env
22
coverage
33
node_modules/
4+
.vscode/*

LICENSE

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ The MIT License (MIT)
22

33
Copyright (c) 2023 Gregor Martynus
44
Copyright (c) 2023 Parker Brown
5+
Copyright (c) 2024 Cristian Lepadatu
56

67
Permission is hereby granted, free of charge, to any person obtaining a copy
78
of this software and associated documentation files (the "Software"), to deal

README.md

+91-34
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
1-
# Create GitHub App Token
1+
# Create GitHub App Token using AWS KMS
22

33
[![test](https://github.com/actions/create-github-app-token/actions/workflows/test.yml/badge.svg)](https://github.com/actions/create-github-app-token/actions/workflows/test.yml)
44

5-
GitHub Action for creating a GitHub App installation access token.
5+
GitHub Action for generating a GitHub App installation access token using AWS KMS in order to safely store the GitHub App private key. This is a fork of vanilla [create-github-app-token](https://github.com/actions/create-github-app-token) action. Unlike the vanilla version, the GitHub App private key is not stored as a secret in GitHub but it is imported in AWS KMS instead as an asymmetric sign-verify customer-managed key. Once imported, it can no longer be retrieved from AWS KMS. However, AWS KMS is capable of signing messages using the key, such as the JWT token used to generate the GitHub App installation access token.
6+
7+
In the vanilla action, the runner has direct access to sensitive information (i.e. the GitHub App private key). In case the runner gets compromised, a malicious actor could potentially get access to sensitive information and run arbitrary API calls, only limited by the GitHub App scope.
8+
9+
This action mitigates this risk by importing the sensitive information in a very secure location (AWS KMS) which does not allow the retrieval of the sensitive information.
10+
11+
>[!IMPORTANT]
12+
>
13+
>Neither this action, nor AWS is responsible for securing access to your AWS account. See the [shared responsibility model](https://docs.aws.amazon.com/whitepapers/latest/aws-risk-and-compliance/shared-responsibility-model.html).
14+
>
15+
>It is highly advised to use temporary AWS credentials scoped to the least privilege when accessing AWS API in order to sign the JWT token.
16+
>
17+
>Using AWS KMS will generate extra costs in your AWS bill.
18+
619

720
## Usage
821

922
In order to use this action, you need to:
1023

1124
1. [Register new GitHub App](https://docs.github.com/apps/creating-github-apps/setting-up-a-github-app/creating-a-github-app)
12-
2. [Store the App's ID in your repository environment variables](https://docs.github.com/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows) (example: `APP_ID`)
13-
3. [Store the App's private key in your repository secrets](https://docs.github.com/actions/security-guides/encrypted-secrets?tool=webui#creating-encrypted-secrets-for-a-repository) (example: `PRIVATE_KEY`)
25+
2. [Store the App's ID in your repository environment variable](https://docs.github.com/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows) or [secret](https://docs.github.com/actions/security-guides/encrypted-secrets?tool=webui#creating-encrypted-secrets-for-a-repository) (example: `APP_ID`)
26+
3. [Import the App's private key in your AWS Account KMS service, under customer-managed keys of type asymmetric, sign-verify, RSA 2048](https://docs.aws.amazon.com/kms/latest/developerguide/importing-keys-create-cmk.html). Once imported in AWS KMS, the GitHub private key can no longer be retrieved from AWS. AWS API can only by asked to sign/verify using the respective key. This substantially improves the security posture, because the key is no longer accessible.
27+
4. [Store the above KMS Key ID as a repository secret](https://docs.github.com/actions/security-guides/encrypted-secrets?tool=webui#creating-encrypted-secrets-for-a-repository) (example `KMS_KEY_ID`)
28+
5. [Store the AWS role to be assumed by the action as a repository secret](https://docs.github.com/actions/security-guides/encrypted-secrets?tool=webui#creating-encrypted-secrets-for-a-repository) (example `ROLE_TO_ASSUME`)
29+
6. [Store the AWS session name as an environment_variable](https://docs.github.com/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows) (example `ROLE_SESSION_NAME`)
30+
7. [Store the AWS region name as an environment_variable](https://docs.github.com/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows) (example `AWS_REGION`)
1431

1532
> [!IMPORTANT]
1633
> An installation access token expires after 1 hour. Please [see this comment](https://github.com/actions/create-github-app-token/issues/121#issuecomment-2043214796) for alternative approaches if you have long-running processes.
@@ -28,11 +45,17 @@ jobs:
2845
hello-world:
2946
runs-on: ubuntu-latest
3047
steps:
48+
- name: AWS Login
49+
uses: aws-actions/configure-aws-credentials@v4
50+
with:
51+
aws-region: ${{ vars.AWS_REGION }}
52+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
53+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
3154
- uses: actions/create-github-app-token@v1
3255
id: app-token
3356
with:
3457
app-id: ${{ vars.APP_ID }}
35-
private-key: ${{ secrets.PRIVATE_KEY }}
58+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
3659
- uses: ./actions/staging-tests
3760
with:
3861
token: ${{ steps.app-token.outputs.token }}
@@ -47,12 +70,18 @@ jobs:
4770
auto-format:
4871
runs-on: ubuntu-latest
4972
steps:
73+
- name: AWS Login
74+
uses: aws-actions/configure-aws-credentials@v4
75+
with:
76+
aws-region: ${{ vars.AWS_REGION }}
77+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
78+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
5079
- uses: actions/create-github-app-token@v1
5180
id: app-token
5281
with:
5382
# required
5483
app-id: ${{ vars.APP_ID }}
55-
private-key: ${{ secrets.PRIVATE_KEY }}
84+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
5685
- uses: actions/checkout@v4
5786
with:
5887
token: ${{ steps.app-token.outputs.token }}
@@ -73,12 +102,18 @@ jobs:
73102
auto-format:
74103
runs-on: ubuntu-latest
75104
steps:
105+
- name: AWS Login
106+
uses: aws-actions/configure-aws-credentials@v4
107+
with:
108+
aws-region: ${{ vars.AWS_REGION }}
109+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
110+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
76111
- uses: actions/create-github-app-token@v1
77112
id: app-token
78113
with:
79114
# required
80115
app-id: ${{ vars.APP_ID }}
81-
private-key: ${{ secrets.PRIVATE_KEY }}
116+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
82117
- name: Get GitHub App User ID
83118
id: get-user-id
84119
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
@@ -98,12 +133,18 @@ jobs:
98133
auto-format:
99134
runs-on: ubuntu-latest
100135
steps:
136+
- name: AWS Login
137+
uses: aws-actions/configure-aws-credentials@v4
138+
with:
139+
aws-region: ${{ vars.AWS_REGION }}
140+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
141+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
101142
- uses: actions/create-github-app-token@v1
102143
id: app-token
103144
with:
104145
# required
105146
app-id: ${{ vars.APP_ID }}
106-
private-key: ${{ secrets.PRIVATE_KEY }}
147+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
107148
- name: Get GitHub App User ID
108149
id: get-user-id
109150
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
@@ -135,11 +176,17 @@ jobs:
135176
hello-world:
136177
runs-on: ubuntu-latest
137178
steps:
179+
- name: AWS Login
180+
uses: aws-actions/configure-aws-credentials@v4
181+
with:
182+
aws-region: ${{ vars.AWS_REGION }}
183+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
184+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
138185
- uses: actions/create-github-app-token@v1
139186
id: app-token
140187
with:
141188
app-id: ${{ vars.APP_ID }}
142-
private-key: ${{ secrets.PRIVATE_KEY }}
189+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
143190
owner: ${{ github.repository_owner }}
144191
- uses: peter-evans/create-or-update-comment@v3
145192
with:
@@ -157,11 +204,17 @@ jobs:
157204
hello-world:
158205
runs-on: ubuntu-latest
159206
steps:
207+
- name: AWS Login
208+
uses: aws-actions/configure-aws-credentials@v4
209+
with:
210+
aws-region: ${{ vars.AWS_REGION }}
211+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
212+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
160213
- uses: actions/create-github-app-token@v1
161214
id: app-token
162215
with:
163216
app-id: ${{ vars.APP_ID }}
164-
private-key: ${{ secrets.PRIVATE_KEY }}
217+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
165218
owner: ${{ github.repository_owner }}
166219
repositories: "repo1,repo2"
167220
- uses: peter-evans/create-or-update-comment@v3
@@ -180,11 +233,17 @@ jobs:
180233
hello-world:
181234
runs-on: ubuntu-latest
182235
steps:
236+
- name: AWS Login
237+
uses: aws-actions/configure-aws-credentials@v4
238+
with:
239+
aws-region: ${{ vars.AWS_REGION }}
240+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
241+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
183242
- uses: actions/create-github-app-token@v1
184243
id: app-token
185244
with:
186245
app-id: ${{ vars.APP_ID }}
187-
private-key: ${{ secrets.PRIVATE_KEY }}
246+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
188247
owner: another-owner
189248
- uses: peter-evans/create-or-update-comment@v3
190249
with:
@@ -221,11 +280,17 @@ jobs:
221280
owners-and-repos: ${{ fromJson(needs.set-matrix.outputs.matrix) }}
222281
223282
steps:
283+
- name: AWS Login
284+
uses: aws-actions/configure-aws-credentials@v4
285+
with:
286+
aws-region: ${{ vars.AWS_REGION }}
287+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
288+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
224289
- uses: actions/create-github-app-token@v1
225290
id: app-token
226291
with:
227292
app-id: ${{ vars.APP_ID }}
228-
private-key: ${{ secrets.PRIVATE_KEY }}
293+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
229294
owner: ${{ matrix.owners-and-repos.owner }}
230295
repositories: ${{ join(matrix.owners-and-repos.repos) }}
231296
- uses: octokit/[email protected]
@@ -249,12 +314,18 @@ jobs:
249314
runs-on: self-hosted
250315
251316
steps:
317+
- name: AWS Login
318+
uses: aws-actions/configure-aws-credentials@v4
319+
with:
320+
aws-region: ${{ vars.AWS_REGION }}
321+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
322+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
252323
- name: Create GitHub App token
253324
id: create_token
254325
uses: actions/create-github-app-token@v1
255326
with:
256327
app-id: ${{ vars.GHES_APP_ID }}
257-
private-key: ${{ secrets.GHES_APP_PRIVATE_KEY }}
328+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
258329
owner: ${{ vars.GHES_INSTALLATION_ORG }}
259330
github-api-url: ${{ vars.GITHUB_API_URL }}
260331
@@ -274,27 +345,9 @@ jobs:
274345

275346
**Required:** GitHub App ID.
276347

277-
### `private-key`
348+
### `kms-key-id`
278349

279-
**Required:** GitHub App private key. Escaped newlines (`\\n`) will be automatically replaced with actual newlines.
280-
281-
Some other actions may require the private key to be Base64 encoded. To avoid recreating a new secret, it can be decoded on the fly, but it needs to be managed securely. Here is an example of how this can be achieved:
282-
283-
```yaml
284-
steps:
285-
- name: Decode the GitHub App Private Key
286-
id: decode
287-
run: |
288-
private_key=$(echo "${{ secrets.PRIVATE_KEY }}" | base64 -d | awk 'BEGIN {ORS="\\n"} {print}' | head -c -2) &> /dev/null
289-
echo "::add-mask::$private_key"
290-
echo "private-key=$private_key" >> "$GITHUB_OUTPUT"
291-
- name: Generate GitHub App Token
292-
id: app-token
293-
uses: actions/create-github-app-token@v1
294-
with:
295-
app-id: ${{ vars.APP_ID }}
296-
private-key: ${{ steps.decode.outputs.private-key }}
297-
```
350+
**Required:** AWS KMS Key ID that is imported from GitHub.
298351

299352
### `owner`
300353

@@ -331,7 +384,11 @@ GitHub App slug.
331384

332385
## How it works
333386

334-
The action creates an installation access token using [the `POST /app/installations/{installation_id}/access_tokens` endpoint](https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app). By default,
387+
The action creates an installation access token using [the `POST /app/installations/{installation_id}/access_tokens` endpoint](https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app).
388+
389+
The action uses the GitHub private key stored in AWS KMS so sign a JWT token and uses this token subsequently for authenticating each GitHub API call, including the one above. Once stored in AWS KMS, the GitHub private key can no longer be retrieved from AWS. AWS API can only by asked to sign/verify using the respective key. This substantially improves the security posture, because the action will no longer access the private key anymore, but ask AWS API to sign/verify instead.
390+
391+
By default,
335392

336393
1. The token is scoped to the current repository or `repositories` if set.
337394
2. The token inherits all the installation's permissions.

action.yml

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
name: "Create GitHub App Token"
2-
description: "GitHub Action for creating a GitHub App installation access token"
3-
author: "Gregor Martynus and Parker Brown"
1+
name: "Create GitHub App Token using AWS KMS"
2+
description: "GitHub Action for creating a GitHub App installation access token using AWS KMS"
3+
author: "Cristian Lepadatu, Gregor Martynus and Parker Brown"
44
branding:
55
icon: "lock"
66
color: "gray-dark"
@@ -12,13 +12,13 @@ inputs:
1212
description: "GitHub App ID"
1313
required: false
1414
deprecationMessage: "'app_id' is deprecated and will be removed in a future version. Use 'app-id' instead."
15-
private-key:
16-
description: "GitHub App private key"
17-
required: false # TODO: When 'private_key' is removed, make 'private-key' required
18-
private_key:
19-
description: "GitHub App private key"
15+
kms-key-id:
16+
description: AWS KMS Key ID"
17+
required: false # TODO: When 'kms_key_id' is removed, make 'kms-key-id' required
18+
kms_key_id:
19+
description: "AWS KMS Key ID"
2020
required: false
21-
deprecationMessage: "'private_key' is deprecated and will be removed in a future version. Use 'private-key' instead."
21+
deprecationMessage: "'kms_key_id' is deprecated and will be removed in a future version. Use 'kms-key-id' instead."
2222
owner:
2323
description: "The owner of the GitHub App installation (defaults to current repository owner)"
2424
required: false

0 commit comments

Comments
 (0)