
Machine ID for GitHub Actions is available starting from Teleport v11.0
.
GitHub Actions is a popular CI/CD platform that works as a part of the larger GitHub ecosystem.
In this guide, you will use Machine ID and the Teleport Kubernetes Service to allow a GitHub Actions workflow to securely connect to a Kubernetes cluster without the need for long-lived secrets.
Teleport supports secure joining on both GitHub-hosted and self-hosted GitHub Actions runners as well as GitHub Enterprise Server.
Prerequisites
-
A running Teleport cluster. For details on how to set this up, see one of our Getting Started guides.
-
The
tctl
admin tool andtsh
client tool version >= 13.0.3.tctl versionTeleport v13.0.3 go1.20
tsh versionTeleport v13.0.3 go1.20
See Installation for details.
-
A running Teleport Enterprise cluster. For details on how to set this up, see our Enterprise Getting Started guide.
-
The Enterprise
tctl
admin tool andtsh
client tool version >= 13.0.3, which you can download by visiting your Teleport account.tctl versionTeleport Enterprise v13.0.3 go1.20
tsh versionTeleport v13.0.3 go1.20
Please use the latest version of Teleport Enterprise documentation.
- Make sure you can connect to Teleport. Log in to your cluster using
tsh
, then usetctl
remotely:tsh login --proxy=teleport.example.com [email protected]tctl statusCluster teleport.example.com
Version 13.0.3
CA pin sha256:abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678
You can run subsequent
tctl
commands in this guide on your local machine.For full privileges, you can also run
tctl
commands on your Auth Service host. - A Kubernetes cluster connected to your Teleport cluster. If you do not already
have one configured, try our
Kubernetes Access getting started guide.
In our examples, this Kubernetes cluster will be named
my-kubernetes-cluster
. - Your Teleport user should have the privileges to create token resources.
- A GitHub repository with GitHub Actions enabled. This guide uses the example
gravitational/example
, and this value should be replaced with your own unique repository.
For self-hosted Teleport Clusters that have non-TLS routing the Kubernetes public address must be set for Machine ID Kubernetes connections.
To confirm the TLS routing mode check the proxy.tls_routing_enabled
from this
command with your proxy address:
curl https://teleport.example.com:443/webapi/ping | jq
The optional tool jq
is used here to help display the JSON output.
If the value proxy.tls_routing_enabled
is false
then non-TLS routing
is set and a Kubernetes public address is required so Machine ID
will connect to the right port. You can confirm the Kubernetes public
address is set if proxy.kube.public_addr
is populated.
The kube_public_addr
is set within the proxy_service
by Teleport administrators:
proxy_service:
enabled: true
kube_listen_addr: 0.0.0.0:3026
kube_public_addr: teleport.example.com:3026
Step 1/4. Create a join token for GitHub Actions
In order to allow your GitHub Actions workflow to authenticate with your Teleport cluster, you'll first need to create a join token. These tokens set out criteria by which the Auth Server decides whether or not to allow a bot or node to join.
To create a token, we can write the resource's YAML to a file on disk, and then
use tctl
to apply it.
Create a file named tokenconfig.yaml
and insert the following contents:
kind: token
version: v2
metadata:
name: github-token
spec:
roles: [Bot]
join_method: github
bot_name: github-demo
github:
allow:
- repository: gravitational/example
From Teleport 11.1.4, users with Teleport Enterprise are able to permit workflows within GitHub Enterprise Server instances to authenticate using the GitHub join method.
This is configured by an additional enterprise_server_host
field in the Token
resource. This should be set to the host of your GHES instance.
kind: token
version: v2
metadata:
name: github-token
spec:
roles: [Bot]
join_method: github
bot_name: github-demo
github:
enterprise_server_host: your.ghes.instance.example.com
allow:
- repository: gravitational/example
Let's go over the token resource YAML's fields in more detail:
metadata.name
defines the name of the token. Note that this value will need to be used in other parts of the configuration later.metadata.expires
defines the date that the join token will expire. This example is set to the year2100
.spec.bot_name
is the name of the Machine ID bot that this token will grant access to. Note that this value will need to be used in other parts of the configuration later.spec.roles
defines which roles that this token will grant access to. The value of[Bot]
states that this token grants access to a Machine ID bot.spec.join_method
defines the join method the token is applicable for. Since this guide only focuses on GitHub Actions, we will set this to togithub
.spec.github.allow
is used to set rules for what GitHub Actions will be able to authenticate by using the token. In this example, thegravitational/example
repository is used, and this example repository should be replaced with your own repo.
You can find a full list of the token configuration options for GitHub Actions joining on the GitHub Actions reference page.
Once the resource file has been written, create the token with tctl
:
tctl create -f tokenconfig.yaml
Check that token github-token
has been created with the following
command:
tctl tokens lsToken Type Labels Expiry Time (UTC)
----------- ---- ------ ----------------------------------------------
github-token Bot 01 Jan 00 00:00 UTC (2562047h47m16.854775807s)
Step 2/4. Create a Machine ID bot
With the join token for the GitHub Actions workflow created, you now need to create a Machine ID bot that the token will grant access to. A Machine ID bot is a special type of Teleport user designed for access by machines, and can authenticate using a join token rather than forms of authentication more suitable to users (e.g. SSO.)
Before creating the bot, first you must create a role in Teleport which grants the bot access to your Kubernetes clusters and defines the Kubernetes RBAC groups that will be added to your bot's requests to the Kubernetes cluster.
Create role.yaml
:
kind: role
metadata:
name: github-demo-kube-access
version: v5
spec:
allow:
kubernetes_labels:
# This grants access to any Kubernetes cluster attached to your Teleport
# cluster.
'*': '*'
kubernetes_groups:
# This group will be attached to requests made by users with this role
# to the Kubernetes API. Configure a cluster role binding that binds this
# group to a Kubernetes cluster role to grant privileges to this Teleport
# role in the Kubernetes cluster.
- github-demo
deny: {}
Note the value provided in kubernetes_groups
. In a later step, you will bind
this group to a Kubernetes role with a cluster role binding.
Apply this to your Teleport cluster:
tctl create -f role.yaml
Now create the Machine ID bot, assigning it the role you created above:
tctl bots add github-demo --roles=github-demo-kube-access --token=github-token
Step 3/4. Configure a Kubernetes cluster role binding
With the bot configured and a Teleport role that will pass a group to Kubernetes with the bot's requests, you now need a role binding to associate a Kubernetes role to that group.
This is the stage where you determine what level of access the bot will have
when accessing your cluster. In our example, we are applying the view
cluster
role which will allow our bot to read, but not write, all resources in the
Kubernetes cluster.
In your case you may want a custom Kubernetes role that lists the exact permissions your bot needs. You can also use a role binding rather than a cluster role binding to limit the bot's access to an individual Kubernetes namespace.
Create a file named clusterolebinding.yaml
:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: github-demo-group
subjects:
- kind: Group
# Name field should match the group configured in the
# `allow.kubernetes_groups` of a role belonging to the user you wish to
# grant access to.
name: github-demo
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
# "view" is a default ClusterRole that grants read-only access to resources
# See: https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles
name: view
apiGroup: rbac.authorization.k8s.io
Create this cluster role binding in your Kubernetes cluster using kubectl
:
$ kubectl apply -f ./clusterolebinding.yaml
Step 4/4. Create the GitHub Actions workflow
With all the configuration in Teleport and Kubernetes complete, you can now create a GitHub Actions workflow that can connect to your Kubernetes cluster.
Our example workflow will list all of the pods contained within the cluster,
but this could just as easily be modified to deploy to a Kubernetes cluster with
kubectl
or helm
.
In the GitHub workflows directory of your repository (.github/workflows/
)
create a new workflow YAML file actionstest.yml
.
Insert the following, replacing my-kubernetes-cluster
with the name of your
Kubernetes cluster and example.domain:443
with the address of your Teleport
Proxy or cloud tenant (e.g. example.teleport.sh
).
# This is a basic workflow to help you get started, modify it for your needs.
on:
push:
branches:
- main
jobs:
demo:
permissions:
# The "id-token: write" permission is required or Machine ID will not be
# able to authenticate with the cluster.
id-token: write
contents: read
name: guide-demo
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/[email protected]
- name: Fetch kubectl
uses: azure/[email protected]
- name: Fetch Teleport binaries
uses: teleport-actions/[email protected]
with:
version: 13.0.3
- name: Fetch credentials using Machine ID
uses: teleport-actions/[email protected]
with:
# Use the address of the auth/proxy server for your own cluster.
proxy: example.domain:443
# Use the name of the join token resource you created in step 1.
token: github-token
# Use the name of your Kubernetes cluster
kubernetes-cluster: my-kubernetes-cluster
# Enable the submission of anonymous usage telemetry.
anonymous-telemetry: 1
- name: List pods
run: kubectl get pods -A
anonymous-telemetry
enables the submission of anonymous usage telemetry. This
helps us shape the future development of tbot
. You can disable this by
omitting this.
The auth-k8s
action sets the KUBECONFIG
for future steps to the credentials
it has fetched from Teleport. This means that most existing tooling for
Kubernetes (e.g kubectl
and helm
) can use your cluster with no additional
configuration.
Add, commit, and push this new workflow file to the default branch of your repository.
Navigate to the Actions tab of your GitHub repository in your web browser.
Select the Workflow that has now been created and triggered by the change,
and select the guide-demo
job.
Expand the List pods step of the action, where you can then confirm that the output shows a list of all the pods within your Kubernetes cluster.
A note on security implications and risk
Once teleport-actions/auth-k8s
has been used in a workflow job, all successive
steps in that job will have access to your Kubernetes cluster as your bot. Where
possible, run as few steps as necessary after this action has been used. It may
be a good idea to break your workflow up into multiple jobs in order to
segregate these credentials from other code running in your CI/CD pipeline.
Most importantly, ensure that the role assigned to your GitHub Actions bot has access to only the resources in your Teleport cluster that your CI/CD needs to interact with.
Next steps
You can find out more about the teleport-action/setup
and
teleport-actions/auth-k8s
actions on their GitHub repositories:
For more information about GitHub Actions itself, read their documentation.