Skip to content

Commit a0418b6

Browse files
authoredOct 12, 2021
Add support for Github App Authentication (#12)
Signed-off-by: Mihai Petracovici <[email protected]>
1 parent be8c26c commit a0418b6

7 files changed

+141
-6
lines changed
 

‎README.md

+8
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ A Runner Token can be used as an alternative to PAT or GitHub App authentication
5959

6060
Refer to [Authenticating with a Runner Token](./docs/runner-token.md).
6161

62+
## Running with Github App Authentication
63+
64+
If you are able to use a GitHub App it is highly recommended over the PAT because you have greater control of the API permissions granted to it and you do not need a bot or service account.
65+
66+
Refer to [Authenticating with GitHub App Authentication](./docs/github-app-authentication.md).
67+
6268
<a id="enterprise-support"></a>
6369

6470
## GitHub Enterprise Support
@@ -92,3 +98,5 @@ If you encounter any other issues, please [open an issue](https://github.com/red
9298

9399
## Credits
94100
This repository builds on the work done in [bbrowning/github-runner](https://github.com/bbrowning/github-runner), which is forked from [SanderKnape/github-runner](https://github.com/SanderKnape/github-runner).
101+
102+
The Github App creation tutorial is heavily based on the excellent README in [actions-runner-controller/actions-runner-controller](https://github.com/actions-runner-controller/actions-runner-controller)

‎base/Containerfile

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ FROM fedora:33
33
# Adapted from https://github.com/bbrowning/github-runner/blob/master/Dockerfile
44
RUN dnf -y upgrade --security && \
55
dnf -y --setopt=skip_missing_names_on_install=False install \
6-
curl git jq hostname procps findutils which && \
6+
curl git jq hostname procps findutils which openssl && \
77
dnf clean all
88

99
# The UID env var should be used in child Containerfile.
@@ -20,6 +20,9 @@ WORKDIR /home/${USERNAME}
2020

2121
# Override these when creating the container.
2222
ENV GITHUB_PAT ""
23+
ENV GITHUB_APP_ID ""
24+
ENV GITHUB_APP_INSTALL_ID ""
25+
ENV GITHUB_APP_PEM ""
2326
ENV GITHUB_OWNER ""
2427
ENV GITHUB_REPOSITORY ""
2528
ENV RUNNER_WORKDIR /home/${USERNAME}/_work
@@ -41,7 +44,7 @@ RUN chown -R ${USERNAME}:0 /home/${USERNAME}/ && \
4144
chgrp -R 0 /home/${USERNAME}/ && \
4245
chmod -R g=u /home/${USERNAME}/
4346

44-
COPY --chown=${USERNAME}:0 entrypoint.sh uid.sh register.sh ./
47+
COPY --chown=${USERNAME}:0 entrypoint.sh uid.sh register.sh get_github_app_token.sh ./
4548

4649
USER $UID
4750

‎base/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Some basic CLI tools are installed in addition to what's in the parent Fedora im
1515
- `git`
1616
- `hostname`
1717
- `jq`
18+
- `openssl`
1819
- `procps` (`ps`, `pgrep`)
1920
- `which`
2021

‎base/entrypoint.sh

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ CREDS_FILE="${PWD}/.credentials"
99

1010
# Assume registration artifacts have been persisted from a previous start
1111
# if no PAT or TOKEN is provided, and simply attempt to start.
12-
if [ -n "${GITHUB_PAT:-}" ] || [ -n "${RUNNER_TOKEN:-}" ]; then
12+
if [ -n "${GITHUB_PAT:-}" ] || [ -n "${RUNNER_TOKEN:-}" ] || [ -n "${GITHUB_APP_ID:-}" ]; then
1313
source ./register.sh
1414
elif [ -e "${CREDS_FILE}" ]; then
1515
echo "No GITHUB_PAT or RUNNER_TOKEN provided. Using existing credentials file ${CREDS_FILE}."
@@ -22,6 +22,9 @@ fi
2222
if [ -n "${GITHUB_PAT:-}" ]; then
2323
trap 'remove; exit 130' INT
2424
trap 'remove; exit 143' TERM
25+
elif [ -n "${GITHUB_APP_ID:-}" ]; then
26+
trap 'remove_github_app; exit 130' INT
27+
trap 'remove_github_app; exit 143' TERM
2528
else
2629
trap 'exit 130' INT
2730
trap 'exit 143' TERM

‎base/get_github_app_token.sh

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/sh
2+
# Adapted from https://stackoverflow.com/a/62646786 and
3+
# Github's docs: https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#authenticating-as-a-github-app
4+
5+
get_github_app_token() {
6+
NOW=$( date +%s )
7+
IAT=$((${NOW} - 60))
8+
EXP=$((${NOW} + 540))
9+
HEADER_RAW='{"alg":"RS256"}'
10+
HEADER=$( echo -n "${HEADER_RAW}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' )
11+
PAYLOAD_RAW='{"iat":'"${IAT}"',"exp":'"${EXP}"',"iss":'"${GITHUB_APP_ID}"'}'
12+
PAYLOAD=$( echo -n "${PAYLOAD_RAW}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' )
13+
HEADER_PAYLOAD="${HEADER}"."${PAYLOAD}"
14+
15+
# Making a tmp directory here because /bin/sh doesn't support process redirection <()
16+
tmp_dir=/tmp/github_app_tmp
17+
mkdir "${tmp_dir}"
18+
echo -n "${GITHUB_APP_PEM}" > "${tmp_dir}/github.pem"
19+
echo -n "${HEADER_PAYLOAD}" > "${tmp_dir}/header"
20+
SIGNATURE=$( openssl dgst -sha256 -sign "${tmp_dir}/github.pem" "${tmp_dir}/header" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' )
21+
rm -rf "${tmp_dir}"
22+
23+
JWT="${HEADER_PAYLOAD}"."${SIGNATURE}"
24+
INSTALL_URL="https://${GITHUB_API_SERVER}/app/installations/${GITHUB_APP_INSTALL_ID}/access_tokens"
25+
INSTALL_TOKEN_PAYLOAD=$(curl -sSfLX POST -H "Authorization: Bearer ${JWT}" -H "Accept: application/vnd.github.v3+json" "${INSTALL_URL}")
26+
INSTALL_TOKEN=$(echo ${INSTALL_TOKEN_PAYLOAD} | jq .token --raw-output)
27+
28+
echo "${INSTALL_TOKEN}"
29+
}

‎base/register.sh

+22-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
set -eE
55

6+
# Load Github app authentication helper function
7+
source ./get_github_app_token.sh
8+
69
if [ -z "${GITHUB_OWNER:-}" ]; then
710
echo "Fatal: \$GITHUB_OWNER must be set in the environment"
811
exit 1
@@ -27,8 +30,8 @@ fi
2730

2831
registration_url="https://${GITHUB_DOMAIN}/${GITHUB_OWNER}${GITHUB_REPOSITORY:+/$GITHUB_REPOSITORY}"
2932

30-
if [ -z "${GITHUB_PAT:-}" ]; then
31-
echo "GITHUB_PAT not set in the environment. Automatic runner removal will be disabled."
33+
if [ -z "${GITHUB_PAT:-}" ] && [ -z "${GITHUB_APP_ID:-}" ]; then
34+
echo "Neither GITHUB_PAT nor the GITHUB_APP variables are set in the environment. Automatic runner removal will be disabled."
3235
echo "Visit ${registration_url}/settings/actions/runners to manually force removal of runner."
3336
fi
3437

@@ -46,7 +49,15 @@ if [ -z "${RUNNER_TOKEN:-}" ]; then
4649
fi
4750
echo "Obtaining runner token from ${token_url}"
4851

49-
payload=$(curl -sSfLX POST -H "Authorization: token ${GITHUB_PAT}" ${token_url})
52+
if [ -n "${GITHUB_APP_ID:-}" ] && [ -n "${GITHUB_APP_INSTALL_ID:-}" ] && [ -n "${GITHUB_APP_PEM:-}" ]; then
53+
echo "GITHUB_APP environment variables are set. Using GitHub App authentication."
54+
app_token=$(get_github_app_token)
55+
payload=$(curl -sSfLX POST -H "Authorization: token ${app_token}" ${token_url})
56+
else
57+
echo "Using GITHUB_PAT for authentication."
58+
payload=$(curl -sSfLX POST -H "Authorization: token ${GITHUB_PAT}" ${token_url})
59+
fi
60+
5061
export RUNNER_TOKEN=$(echo $payload | jq .token --raw-output)
5162
echo "Obtained registration token"
5263
else
@@ -79,3 +90,11 @@ remove() {
7990

8091
./config.sh remove --unattended --token "${REMOVE_TOKEN}"
8192
}
93+
94+
remove_github_app() {
95+
app_token=$(get_github_app_token)
96+
payload=$(curl -sSfLX POST -H "Authorization: token ${app_token}" ${token_url%/registration-token}/remove-token)
97+
export REMOVE_TOKEN=$(echo $payload | jq .token --raw-output)
98+
99+
./config.sh remove --unattended --token "${REMOVE_TOKEN}"
100+
}

‎docs/github-app-authentication.md

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
## Setting up a GitHub App for Runner Registration
2+
3+
You can create a GitHub App for your user account, or any organization.
4+
5+
The following app permissions are required for each supported type of runner:
6+
7+
_Note: Links are provided further down to create an app for your logged in user account or an organization with the permissions for all runner types set in each link's query string_
8+
9+
**Required Permissions for Repository Runners:**<br />
10+
**Repository Permissions**
11+
12+
* Actions (read)
13+
* Administration (read / write)
14+
* Metadata (read)
15+
16+
**Required Permissions for Organization Runners:**<br />
17+
**Repository Permissions**
18+
19+
* Actions (read)
20+
* Metadata (read)
21+
22+
**Organization Permissions**
23+
* Self-hosted runners (read / write)
24+
25+
26+
_Note: All API routes mapped to their permissions can be found [here](https://docs.github.com/en/rest/reference/permissions-required-for-github-apps) if you wish to review_
27+
28+
---
29+
30+
**Setup Steps**
31+
32+
If you want to create a GitHub App for your account, open the following link to the creation page, enter any unique name in the "GitHub App name" field, and hit the "Create GitHub App" button at the bottom of the page.
33+
34+
<!-- markdown-link-check-disable-next-line -->
35+
- [Create GitHub Apps on your account](https://github.com/settings/apps/new?url=https://github.com/redhat-actions/openshift-actions-runners&webhook_active=false&public=false&administration=write&actions=read)
36+
37+
If you want to create a GitHub App for your organization, replace the `:org` part of the following URL with your organization name before opening it. Then enter any unique name in the "GitHub App name" field, and hit the "Create GitHub App" button at the bottom of the page to create a GitHub App.
38+
39+
<!-- markdown-link-check-disable-next-line -->
40+
- [Create GitHub Apps on your organization](https://github.com/organizations/:org/settings/apps/new?url=https://github.com/redhat-actions/openshift-actions-runners&webhook_active=false&public=false&administration=write&organization_self_hosted_runners=write&actions=read)
41+
42+
You will see an *App ID* on the page of the GitHub App you created. You will need the value of this App ID later.
43+
44+
Download the private key file by pushing the "Generate a private key" button at the bottom of the GitHub App page. This file will also be used later.
45+
46+
Go to the "Install App" tab on the left side of the page and install the GitHub App that you created for your account or organization.
47+
48+
When the installation is complete, you will be taken to a URL in one of the following formats. The number at the end of the URL will be used as the Installation ID later.
49+
50+
For example, if the URL ends in `settings/installations/12345`, then the Installation ID is `12345`.
51+
52+
- `https://github.com/settings/installations/${INSTALLATION_ID}`
53+
- `https://github.com/organizations/eventreactor/settings/installations/${INSTALLATION_ID}`
54+
55+
### Running Locally with GitHub App Authentication
56+
57+
You need to set the `GITHUB_APP_ID`, `GITHUB_APP_INSTALL_ID`, and `GITHUB_APP_PEM` env variables and pass them to your container.
58+
59+
The easiest way to get the private key in the correct form is to copy paste it into the environment variable. Newlines must be preserved.
60+
61+
To launch and connect a runner to `redhat-actions/openshift-actions-runner` with the labels `local` and `podman`:
62+
63+
```sh
64+
podman run \
65+
--env GITHUB_APP_ID \
66+
--env GITHUB_APP_INSTALL_ID \
67+
--env GITHUB_APP_PEM \
68+
--env GITHUB_OWNER=redhat-actions \
69+
--env GITHUB_REPOSITORY=openshift-actions-runner \
70+
--env RUNNER_LABELS="local,podman" \
71+
quay.io/redhat-github-actions/runner:latest
72+
```

0 commit comments

Comments
 (0)
Please sign in to comment.