Deploying Machine ID on GitHub Actions
GitHub Actions is a popular CI/CD platform that works as a part of the larger GitHub ecosystem. Teleport Machine ID allows GitHub Actions to securely interact with Teleport protected resources without the need for long-lived credentials.
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 version 17.0.0-dev or above. If you want to get started with Teleport, sign up for a free trial or set up a demo environment.
-
The
tctl
admin tool andtsh
client tool.Visit Installation for instructions on downloading
tctl
andtsh
.
- To check that you can connect to your Teleport cluster, sign in with
tsh login
, then verify that you can runtctl
commands using your current credentials. For example:If you can connect to the cluster and run the$ tsh login --proxy=teleport.example.com [email protected]
$ tctl status
# Cluster teleport.example.com
# Version 17.0.0-dev
# CA pin sha256:abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678tctl status
command, you can use your current credentials to run subsequenttctl
commands from your workstation. If you host your own Teleport cluster, you can also runtctl
commands on the computer that hosts the Teleport Auth Service for full permissions. - Your user should have the privileges to create token resources.
- A GitHub repository with GitHub Actions enabled. This guide uses the example
gravitational/example
repo, however this value should be replaced with your own unique repo.
Step 1/3. Create a Bot
Next, you need to create a Bot. A Bot is a Teleport identity for a machine or group of machines. Like users, bots have a set of roles and traits which define what they can access.
Create bot.yaml
:
kind: bot
version: v1
metadata:
# name is a unique identifier for the Bot in the cluster.
name: example
spec:
# roles is a list of roles to grant to the Bot. Don't worry if you don't know
# what roles you need to specify here, the Access Guides will walk you through
# creating and assigning roles to the already created Bot.
roles: []
Make sure you replace example
with a unique, descriptive name for your Bot.
Use tctl
to apply this file:
$ tctl create bot.yaml
Step 2/3. 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 to allow a bot or node to join.
In this example, you will create a join token that grants access to any GitHub Actions run within a specific GitHub repository. In production, you may wish to further restrict these rules to ensure that access can only occur when CI is running against a specific branch. You can find a full list of the available rules on the GitHub Actions reference page.
Create a file named bot-token.yaml
:
kind: token
version: v2
metadata:
name: example-bot
spec:
# The Bot role indicates that this token grants access to a bot user, rather
# than allowing a node to join. This role is built in to Teleport.
roles: [Bot]
join_method: github
# The bot_name indicates which bot user this token grants access to. This
# should match the name of the bot that you created in the previous step.
bot_name: example
github:
# allow specifies rules that control which GitHub Actions runs will be
# granted access. Those not matching any allow rule will be denied.
allow:
# repository should include the name of the owner of the repository.
- repository: gravitational/example
Replace gravitational/example
with the name of the repository that tbot
will run within. You may also choose to change the name of the bot and token
to more accurately describe your use-case.
Enterprise Server
If you are using self-hosted Teleport Enterprise you are able to permit workflows within GitHub Enterprise Server instances to authenticate using the GitHub join method.
The Teleport Auth Server must be able to connect to the GitHub Enterprise Server.
To configure this, set spec.github.enterprise_server_host
to the hostname of
the GHES instance.
For example:
spec:
github:
enterprise_server_host: ghes.example.com
Enterprise Cloud
If you have enabled include_enterprise_slug
in your GitHub Enterprise
Cloud configuration, you will need to set spec.github.enterprise_slug
to
the slug of your GitHub Enterprise organization.
For example:
spec:
github:
enterprise_slug: my-enterprise
Read more about include_enterprise_slug
on the GitHub guide to
customizing the issuer value for an enterprise.
Once the resource file has been written, create the token with tctl
:
$ tctl create -f bot-token.yaml
Check that token example-bot
has been created with the following
command:
$ tctl tokens ls
Token Type Labels Expiry Time (UTC)
----------- ---- ------ ----------------------------------------------
example-bot Bot 01 Jan 00 00:00 UTC (2562047h47m16.854775807s)
Step 3/3. Configure a GitHub Actions Workflow
Now that the bot has been successfully created, you now need to configure your
GitHub Action's workflow to authenticate as this bot and then use the
credentials produced by tbot
. To help with this, Teleport publishes
several easy-to-use GitHub Actions that can be used within your workflow.
It is also possible to manually configure tbot
rather than using one of the
Teleport GitHub Actions. This involves more configuration but allows for
precise control of tbot
and allows for implementations that are not possible
with the actions.
What follows is examples demonstrating two of the GitHub Actions available as
well as showing how to manually configure tbot
for use with GitHub Actions.
Example: teleport-actions/auth
The teleport-actions/auth
action generates a versatile identity output that
can be used for SSH and for administrative actions against a Teleport cluster.
Environment variables are configured by this action and these automatically
configure tsh
and tctl
to use this identity.
This example shows using the credentials to:
- List the SSH nodes available using
tsh
- List the SSH nodes available using
tctl
- Connect to an SSH node using
tsh
- Connect to an SSH node using OpenSSH's
ssh
First, you'll need to adjust the role you assigned to the bot to grant it access to SSH. This example grants access to root on all nodes. In a production setup, it would be a good idea to restrict this to only the nodes that the bot would need.
Use tctl edit role/example-bot
to add the following to the role:
spec:
allow:
# Allow login to the Linux user 'root'.
logins: ['root']
# Allow connection to any node. Adjust these labels to match only nodes
# that ansible needs to access.
node_labels:
'*': '*'
With that privileges granted, you can now create the GitHub Actions workflow.
Create .github/workflows/example.yaml
:
# This is a basic workflow to help you get started.
# It will take the following action whenever a push is made to the "main" branch.
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
# The name of the workflow, and the Linux distro to be used to perform the
# required steps.
name: example
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Fetch Teleport binaries
uses: teleport-actions/setup@v1
with:
version: 17.0.0-dev
- name: Fetch credentials using Machine ID
id: auth
uses: teleport-actions/auth@v2
with:
# Use the address of the auth/proxy server for your own cluster.
proxy: example.teleport.sh:443
# Use the name of the join token resource you created in step 1.
token: example-bot
# Specify the length of time that the generated credentials should be
# valid for. This is optional and defaults to "1h"
certificate-ttl: 1h
# Enable the submission of anonymous usage telemetry. This
# helps us shape the future development of `tbot`. You can disable this
# by omitting this.
anonymous-telemetry: 1
- name: List nodes (tsh)
# Enters a command from the cluster, in this case "tsh ls" using Machine
# ID credentials to list remote SSH nodes.
run: tsh ls
- name: List nodes (tctl)
run: tctl nodes ls
- name: Run hostname via SSH (tsh)
# Ensure that `root` matches the username of a remote SSH username, and
# that hostname matches an SSH host name that is a part of the Teleport
# cluster configured for access.
run: tsh ssh root@example-node hostname
- name: Run hostname via SSH (OpenSSH)
run: ssh -F ${{ steps.auth.outputs.ssh-config }} root@example-node.example.teleport.sh hostname
Replace:
example.teleport.sh:443
with the address of your Teleport Proxy or cloud tenant.example-bot
with the name of the token you created in a previous step.example-node
with the name of a Teleport SSH node that you wish to connect to.root
with the name of a user on the node that you are connecting to and that you have granted the bot access to.
Add, commit, and push your changes to the main
branch of the 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 example
job. The GitHub Actions workflow may take some time
to complete, and will resemble the following once successful.
Expand the List nodes step of the action, and the output will
list all nodes in the cluster, from the perspective of the
Machine ID bot using the command tsh ls
.
Example: teleport-actions/auth-k8s
The teleport-actions/auth-k8s
action generates a Kubernetes output that
contains the necessary credentials and config for a Kubernetes client to connect
to a Kubernetes cluster enrolled in Teleport. The action emits the necessary
environment variable to automatically configure these clients.
In this example, the teleport-actions/auth-k8s
action will be used to list
all the pods contained within the cluster, but this could just as easily be
modified to deploy to a Kubernetes cluster with kubectl
or helm
.
First, you'll need to adjust the role you assigned to the bot to grant it access
to the Kubernetes cluster. This example will grant the bot access to all
clusters with the group editor
. For more detailed instructions on setting
up Kubernetes RBAC, see the Kubernetes access guide.
Use tctl edit role/example-bot
to add the following rule to the Teleport role:
spec:
allow:
kubernetes_labels:
'*': '*'
kubernetes_resources:
- kind: pod
namespace: "*"
name: "*"
kubernetes_groups:
- editor
This example assumes the role is version v6
. If you are using a v7
+ role
you will need to include verbs: ["get", "list"]
for the kind: pod
section
in kubernetes_resources
. Otherwise the example kubectl get pods -A
execution
will be denied.
With that privileges granted, you can now create the GitHub Actions workflow.
Create .github/workflows/example.yaml
:
# 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: example
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Fetch kubectl
uses: azure/setup-kubectl@v3
- name: Fetch Teleport binaries
uses: teleport-actions/setup@v1
with:
version: 17.0.0-dev
- name: Fetch credentials using Machine ID
uses: teleport-actions/auth-k8s@v2
with:
# Use the address of the auth/proxy server for your own cluster.
proxy: example.teleport.sh:443
# Use the name of the join token resource you created in step 1.
token: example-bot
# Use the name of your Kubernetes cluster
kubernetes-cluster: my-kubernetes-cluster
# Enable the submission of anonymous usage telemetry. This helps us
# shape the future development of `tbot`. You can disable this by
# omitting this.
anonymous-telemetry: 1
- name: List pods
run: kubectl get pods -A
Replace:
example.teleport.sh:443
with the address of your Teleport Proxy or cloud tenant.example-bot
with the name of the token you created in a previous step.my-kubernetes-cluster
with the name of your Kubernetes cluster.
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 example
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.
Example: Manual configuration
To configure tbot
manually, a YAML file will be used. In this example we'll
commit this to the repository, but this could be generated or created by the
CI pipeline itself.
Create tbot.yaml
within your repository:
version: v2
proxy_server: example.teleport.sh:443
onboarding:
join_method: github
token: example-bot
oneshot: true
storage:
type: memory
# outputs will be filled in during the completion of an access guide.
outputs: []
Replace:
example.teleport.sh:443
with the address of your Teleport Proxy or Auth Server. Prefer using the address of a Teleport Proxy.example-bot
with the name of the token you created in the first step.
Now you can define a GitHub Actions workflow that will start tbot
with this
configuration.
Create .github/workflows/example-action.yaml
:
# This is a basic workflow to help you get started.
# It will take the following action whenever a push is made to the "main" branch.
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
# The name of the workflow, and the Linux distro to be used to perform the
# required steps.
name: guide-demo
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Fetch Teleport binaries
uses: teleport-actions/setup@v1
with:
version: 17.0.0-dev
- name: Execute Machine ID
env:
# TELEPORT_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.
TELEPORT_ANONYMOUS_TELEMETRY: 1
run: tbot start -c ./tbot.yaml --oneshot
Add, commit, and push these two files to the repository. Check the GitHub Actions UI to ensure that the workflow has succeeded.
You have now prepared the base configuration for tbot
. At this point, it
identifies itself to the Teleport cluster and renews its own credentials but
does not output any credentials for other applications to use.
Follow one of the access guides to configure an output that meets your access needs.
A note on security implications and risk
Once teleport-actions/auth
has been used in a workflow job, all successive
steps in that job will have access to the credentials which grant access to your
Teleport cluster as the 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 you assign 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
- Check out the GitHub Actions for more usage information:
- For more information about the
github
join method, read the GitHub Actions reference page - Find out more about GitHub Actions itself, read their documentation.
- More information about
anonymous-telemetry
.