1
0
mirror of https://github.com/tektoncd/catalog.git synced 2024-11-21 05:55:35 +00:00

Add github app token 0.2

Added a new params to allow getting the application_id from the secrets
workspace, still allowing as params directly if user would like to use
this instead.

Signed-off-by: Chmouel Boudjnah <chmouel@redhat.com>
This commit is contained in:
Chmouel Boudjnah 2021-04-26 17:04:58 +02:00 committed by tekton-robot
parent 94aede7853
commit 0a59b634f7
5 changed files with 248 additions and 0 deletions

View File

@ -0,0 +1,9 @@
FROM python:3.8-alpine as build
RUN apk update && apk upgrade && pip install -U pip && \
apk add --update alpine-sdk make gcc python3-dev libffi-dev openssl-dev \
&& rm -rf /var/cache/apk/*
RUN pip --no-cache-dir install requests jwcrypto
FROM python:3.8-alpine
COPY --from=build /usr/local/share /usr/local/share
COPY --from=build /usr/local/lib /usr/local/lib

View File

@ -0,0 +1,42 @@
# GitHub app token
A task to get a user token from a github application
## Workspaces
- **secrets**: A workspace containing the private key of the application.
## Secret
This GitHub applications needs a private key to sign your request with JWT.
[This](../0.2/samples/secret.yaml) example can be referred to create the secret
Refer [this](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html) guide for setting up AWS Credentials and Region.
## Params
* **installation_id:** The GitHub app installation ID _eg:_ `123456`
* **application_id:** The GitHub application ID. _e.g:_ `123456`
* **private_key_path:** The path to the key inside the secret workspace, _default:_
`private.key`
* **application_id_path:** The path to installation_id inside the secret workspace, it will use it if it can find it or use the params.application_id instead, _default:_ `application_id_path`
* **token_expiration_minutes:**: The time to expirations of the token in minutes _default:_ `10`
### Install the Task
```
kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/github-app-token/0.2/github-app-token.yaml
```
## Usage
After creating the task with the parameters, you should have the token as result in the task which can
be used in your pipeline to do github operations from the app as the target user.
See [this](../0.2/samples/run.yaml) taskrun example on how to start the task directly.

View File

@ -0,0 +1,159 @@
# TODO: Submit this in catalog upstream
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: github-app-token
labels:
app.kubernetes.io/version: "0.2"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: github
tekton.dev/displayName: "github app token"
spec:
description: >-
Retrive a user token from a GitHub application
This task will get a user token for an installation_id for a GitHub application.
This could be then reuse to do user operations.
workspaces:
- name: secrets
results:
- name: token
description: The user token to use.
params:
- name: installation_id
description: The installation id for the GitHub application to request a token for.
type: string
- name: application_id
description: The application id for the GitHub application to request a token for.
type: string
default: ""
- name: private_key_path
description: The key path inside the secret workspace
type: string
default: "private.key"
- name: application_id_path
description: The path for the application id inside the secret workspace
type: string
default: "application_id"
- name: token_expiration_minutes
description: Token expiration time in minutes
type: string
default: "10"
steps:
- name: get-token
image: quay.io/chmouel/github-app-token@sha256:bc45937ae588df876555ebb56c36350ed74592c7f55f2df255cabef39c926a88
env:
- name: GITHUBAPP_KEY_PATH
value: $(workspaces.secrets.path)/$(params.private_key_path)
- name: GITHUBAPP_APP_ID_PATH
value: $(workspaces.secrets.path)/$(params.application_id_path)
- name: GITHUBAPP_APP_ID
value: $(params.application_id)
- name: GITHUBAPP_INSTALLATION_ID
value: $(params.installation_id)
- name: GITHUBAPP_TOKEN_EXPIRATION_MINUTES
value: $(params.token_expiration_minutes)
- name: GITHUBAPP_RESULT_PATH
value: $(results.token.path)
script: |
#!/usr/bin/env python3
import json
import os
import time
import requests
from jwcrypto import jwk, jwt
EXPIRE_MINUTES_AS_SECONDS = int(os.environ.get('GITHUBAPP_TOKEN_EXPIRATION_MINUTES', 10)) * 60
# TODO support github enteprise
GITHUB_API_URL = "https://api.github.com"
class GitHub():
token = None
def __init__(self, private_key, app_id=None, installation_id=None):
if not isinstance(private_key, bytes):
raise ValueError(f'"{private_key}" parameter must be byte-string')
self._private_key = private_key
self.app_id = app_id
self.token = self._get_token(installation_id)
def _load_private_key(self, pem_key_bytes):
return jwk.JWK.from_pem(pem_key_bytes)
def _app_token(self, expire_in=EXPIRE_MINUTES_AS_SECONDS):
key = self._load_private_key(self._private_key)
now = int(time.time())
token = jwt.JWT(
header={"alg": "RS256"},
claims={
"iat": now,
"exp": now + expire_in,
"iss": self.app_id
},
algs=["RS256"],
)
token.make_signed_token(key)
return token.serialize()
def _get_token(self, installation_id=None):
app_token = self._app_token()
if not installation_id:
return app_token
req = self._request(
"POST",
f"/app/installations/{installation_id}/access_tokens",
headers={
"Authorization": f"Bearer {app_token}",
"Accept": "application/vnd.github.machine-man-preview+json"
})
ret = req.json()
if 'token' not in ret:
raise Exception("Authentication errors")
return ret['token']
def _request(self, method, url, headers={}, data={}):
if self.token and 'Authorization' not in headers:
headers.update({"Authorization": "Bearer " + self.token})
if not url.startswith("http"):
url = f"{GITHUB_API_URL}{url}"
return requests.request(method,
url,
headers=headers,
data=json.dumps(data))
def main():
with open(os.environ['GITHUBAPP_KEY_PATH'], 'rb') as key_file:
key = key_file.read()
if os.path.exists(os.environ['GITHUBAPP_APP_ID_PATH']):
app_id = open(os.environ['GITHUBAPP_APP_ID_PATH']).read()
elif os.environ.get('GITHUBAPP_APP_ID'):
app_id = os.environ['GITHUBAPP_APP_ID']
else:
raise Exception("application id is not set")
print(f"Getting user token for application_id: {app_id}")
github_app = GitHub(
key,
app_id=app_id,
installation_id=os.environ.get('GITHUBAPP_INSTALLATION_ID'))
open(os.environ.get('GITHUBAPP_RESULT_PATH'), 'w').write(github_app.token)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,16 @@
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
generateName: github-app-token-
spec:
taskRef:
name: github-app-token
params:
- name: installation_id
value: 12345
- name: application_id
value: 67890
workspaces:
- name: secrets
secret:
secretName: github-app-secret

View File

@ -0,0 +1,22 @@
apiVersion: v1
kind: Secret
metadata:
name: github-app-secret
type: Opaque
stringData:
private.key: |-
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCxiQEUg+S3LmCUDVUaa6q1GM5+phvoL4UXkzr8aa1VZGJCWEEQ
ualGonn5DmCN99NPIuQRZwMa8xLT0yShGPqar9XxGpoinejrxbL10tqQ20EfBDB9
z1duIaXsdCckq/oyvpsSH6akQddzzQCXSHYRZI1UQVyiFRYQyJhjcRSyRQIDAQAB
AoGAOqVITw+WsRBH5QBWeYjRdktAg0O5+kQgUf5XwOPj1052yvW+YJkEGwo3ApfG
O39/NSgQcNM3imJ7eK/J7NGEjqAjwZwlLWgAe5LeLYctJG6GhRyDkQ1dui8UJg4X
Wmq+kRcfExKSy1qAwDi1jRvK9dEjxwZdDJNGdIfpWLHH0W0CQQD5vPUBF2dNwXOs
KN8qyPQ4LhgH/EeexM40d5knkgKZ2+9VthdG9VEhdigz2MH/CwI20IsnXwY84lAB
uaODjADjAkEAtfyVgcM7DobOucuMEyj+nH0E8GUBwiQ1O0gFA79Uoii39f0cydeO
TqZwgrPa/oSF76w0dZMZ+m9spjX5zEywtwJAIKNeTb82RAY1TNmmmNvcdv8nKtwA
rDJCVL8QqAhACMWimMwMbLyg1sOva183s1JH/svwc7vKf+h/1knhoc6JSwJBALW0
Eyaz4lRXvzJ9DEfZJ5bhsLvBbicEde3Rs8gREhSyqTK/3S2evqTCxBWMNHzpnr01
6E74Z/jHpeiyfc5BSDMCQEegoccNEAtBNl48gfSDVvFCBpDePIQoqC90j6xHx++O
NZsjlNUJXgVQZ5ghrGCQEc6beTvBSIEeNvwxX7S1h04=
-----END RSA PRIVATE KEY-----