No More Backdoors: Know Who Has Access to What, Right Now
Jun 13
Virtual
Register Today
Teleport logoTry For Free
Fork me on GitHub

Teleport

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 16.0.0 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 and tsh client tool.

    Visit Installation for instructions on downloading tctl and tsh.

  • To check that you can connect to your Teleport cluster, sign in with tsh login, then verify that you can run tctl commands using your current credentials. tctl is supported on macOS and Linux machines. For example:
    tsh login --proxy=teleport.example.com --user=[email protected]
    tctl status

    Cluster teleport.example.com

    Version 16.0.0

    CA pin sha256:abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678

    If you can connect to the cluster and run the tctl status command, you can use your current credentials to run subsequent tctl commands from your workstation. If you host your own Teleport cluster, you can also run tctl 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.

Using GitHub Enterprise?

Enterprise Server

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.

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: 16.0.0
    - 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 }} [email protected] 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

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: 16.0.0
    - 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: 16.0.0
    - 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