Skip to content

Commit c8be728

Browse files
committed
First release
1 parent 9ccc6db commit c8be728

14 files changed

+1565
-154
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/request-action@v2.x
4861
id: get-repository
4962
env:

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

+77-33
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@
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 creating a GitHub App installation access token using AWS KMS in order to safely store the GitHub repositry private key.
66

77
## Usage
88

99
In order to use this action, you need to:
1010

1111
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`)
12+
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`)
13+
3. [Import the App's private key in your AWS Account KMS service, under customer-managed keys of type assymetric, sign-verify](https://docs.aws.amazon.com/kms/latest/developerguide/importing-keys-create-cmk.html)
14+
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`). Once stored in AWS KMS, the GitHub private key can no longer be retieved 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.
15+
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`)
16+
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`)
17+
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`)
1418

1519
> [!IMPORTANT]
1620
> 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 +32,17 @@ jobs:
2832
hello-world:
2933
runs-on: ubuntu-latest
3034
steps:
35+
- name: AWS Login
36+
uses: aws-actions/configure-aws-credentials@v4
37+
with:
38+
aws-region: ${{ vars.AWS_REGION }}
39+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
40+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
3141
- uses: actions/create-github-app-token@v1
3242
id: app-token
3343
with:
3444
app-id: ${{ vars.APP_ID }}
35-
private-key: ${{ secrets.PRIVATE_KEY }}
45+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
3646
- uses: ./actions/staging-tests
3747
with:
3848
token: ${{ steps.app-token.outputs.token }}
@@ -47,12 +57,18 @@ jobs:
4757
auto-format:
4858
runs-on: ubuntu-latest
4959
steps:
60+
- name: AWS Login
61+
uses: aws-actions/configure-aws-credentials@v4
62+
with:
63+
aws-region: ${{ vars.AWS_REGION }}
64+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
65+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
5066
- uses: actions/create-github-app-token@v1
5167
id: app-token
5268
with:
5369
# required
5470
app-id: ${{ vars.APP_ID }}
55-
private-key: ${{ secrets.PRIVATE_KEY }}
71+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
5672
- uses: actions/checkout@v4
5773
with:
5874
token: ${{ steps.app-token.outputs.token }}
@@ -73,12 +89,18 @@ jobs:
7389
auto-format:
7490
runs-on: ubuntu-latest
7591
steps:
92+
- name: AWS Login
93+
uses: aws-actions/configure-aws-credentials@v4
94+
with:
95+
aws-region: ${{ vars.AWS_REGION }}
96+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
97+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
7698
- uses: actions/create-github-app-token@v1
7799
id: app-token
78100
with:
79101
# required
80102
app-id: ${{ vars.APP_ID }}
81-
private-key: ${{ secrets.PRIVATE_KEY }}
103+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
82104
- name: Get GitHub App User ID
83105
id: get-user-id
84106
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
@@ -98,12 +120,18 @@ jobs:
98120
auto-format:
99121
runs-on: ubuntu-latest
100122
steps:
123+
- name: AWS Login
124+
uses: aws-actions/configure-aws-credentials@v4
125+
with:
126+
aws-region: ${{ vars.AWS_REGION }}
127+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
128+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
101129
- uses: actions/create-github-app-token@v1
102130
id: app-token
103131
with:
104132
# required
105133
app-id: ${{ vars.APP_ID }}
106-
private-key: ${{ secrets.PRIVATE_KEY }}
134+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
107135
- name: Get GitHub App User ID
108136
id: get-user-id
109137
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
@@ -135,11 +163,17 @@ jobs:
135163
hello-world:
136164
runs-on: ubuntu-latest
137165
steps:
166+
- name: AWS Login
167+
uses: aws-actions/configure-aws-credentials@v4
168+
with:
169+
aws-region: ${{ vars.AWS_REGION }}
170+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
171+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
138172
- uses: actions/create-github-app-token@v1
139173
id: app-token
140174
with:
141175
app-id: ${{ vars.APP_ID }}
142-
private-key: ${{ secrets.PRIVATE_KEY }}
176+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
143177
owner: ${{ github.repository_owner }}
144178
- uses: peter-evans/create-or-update-comment@v3
145179
with:
@@ -157,11 +191,17 @@ jobs:
157191
hello-world:
158192
runs-on: ubuntu-latest
159193
steps:
194+
- name: AWS Login
195+
uses: aws-actions/configure-aws-credentials@v4
196+
with:
197+
aws-region: ${{ vars.AWS_REGION }}
198+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
199+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
160200
- uses: actions/create-github-app-token@v1
161201
id: app-token
162202
with:
163203
app-id: ${{ vars.APP_ID }}
164-
private-key: ${{ secrets.PRIVATE_KEY }}
204+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
165205
owner: ${{ github.repository_owner }}
166206
repositories: "repo1,repo2"
167207
- uses: peter-evans/create-or-update-comment@v3
@@ -180,11 +220,17 @@ jobs:
180220
hello-world:
181221
runs-on: ubuntu-latest
182222
steps:
223+
- name: AWS Login
224+
uses: aws-actions/configure-aws-credentials@v4
225+
with:
226+
aws-region: ${{ vars.AWS_REGION }}
227+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
228+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
183229
- uses: actions/create-github-app-token@v1
184230
id: app-token
185231
with:
186232
app-id: ${{ vars.APP_ID }}
187-
private-key: ${{ secrets.PRIVATE_KEY }}
233+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
188234
owner: another-owner
189235
- uses: peter-evans/create-or-update-comment@v3
190236
with:
@@ -221,11 +267,17 @@ jobs:
221267
owners-and-repos: ${{ fromJson(needs.set-matrix.outputs.matrix) }}
222268
223269
steps:
270+
- name: AWS Login
271+
uses: aws-actions/configure-aws-credentials@v4
272+
with:
273+
aws-region: ${{ vars.AWS_REGION }}
274+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
275+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
224276
- uses: actions/create-github-app-token@v1
225277
id: app-token
226278
with:
227279
app-id: ${{ vars.APP_ID }}
228-
private-key: ${{ secrets.PRIVATE_KEY }}
280+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
229281
owner: ${{ matrix.owners-and-repos.owner }}
230282
repositories: ${{ join(matrix.owners-and-repos.repos) }}
231283
- uses: octokit/request-action@v2.x
@@ -249,12 +301,18 @@ jobs:
249301
runs-on: self-hosted
250302
251303
steps:
304+
- name: AWS Login
305+
uses: aws-actions/configure-aws-credentials@v4
306+
with:
307+
aws-region: ${{ vars.AWS_REGION }}
308+
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
309+
role-session-name: ${{ vars.ROLE_SESSION_NAME }}
252310
- name: Create GitHub App token
253311
id: create_token
254312
uses: actions/create-github-app-token@v1
255313
with:
256314
app-id: ${{ vars.GHES_APP_ID }}
257-
private-key: ${{ secrets.GHES_APP_PRIVATE_KEY }}
315+
kms-key-id: ${{ secrets.KMS_KEY_ID }}
258316
owner: ${{ vars.GHES_INSTALLATION_ORG }}
259317
github-api-url: ${{ vars.GITHUB_API_URL }}
260318
@@ -274,27 +332,9 @@ jobs:
274332

275333
**Required:** GitHub App ID.
276334

277-
### `private-key`
278-
279-
**Required:** GitHub App private key. Escaped newlines (`\\n`) will be automatically replaced with actual newlines.
335+
### `kms-key-id`
280336

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-
```
337+
**Required:** AWS KMS Key ID that is imported from GitHub.
298338

299339
### `owner`
300340

@@ -331,7 +371,11 @@ GitHub App slug.
331371

332372
## How it works
333373

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,
374+
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).
375+
376+
The action uses the GitHub private key stored in AWS KMS so sign a JWT token and uses this token subsequently for autheticating each GitHub API call, including the one above. Once stored in AWS KMS, the GitHub private key can no longer be retieved 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.
377+
378+
By default,
335379

336380
1. The token is scoped to the current repository or `repositories` if set.
337381
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)