Fork me on GitHub

Teleport

Using Machine ID with CircleCI

Improve

Machine ID for CircleCI is available starting from Teleport v11.1.

In this guide, you will use Teleport Machine ID to allow a CircleCI job to securely connect to a Teleport SSH node without the need for long-lived secrets.

This mitigates the risk of long-lived secrets such as passwords or SSH private keys being exfiltrated from your CircleCI organization and provides many of the other benefits of Teleport such as auditing and finely-grained access control.

Prerequisites

  • A running Teleport cluster. For details on how to set this up, see one of our Getting Started guides.

  • The tctl admin tool and tsh client tool version >= 11.3.1.

    tctl version

    Teleport v11.3.1 go1.19

    tsh version

    Teleport v11.3.1 go1.19

    See Installation for details.

  • A running Teleport cluster. For details on how to set this up, see our Enterprise Getting Started guide.

  • The tctl admin tool and tsh client tool version >= 11.3.1, which you can download by visiting the customer portal.

    tctl version

    Teleport v11.3.1 go1.19

    tsh version

    Teleport v11.3.1 go1.19

  • A Teleport Cloud account. If you do not have one, visit the sign up page to begin your free trial.

  • The tctl admin tool and tsh client tool version >= 11.2.1. To download these tools, visit the Downloads page.

    tctl version

    Teleport v11.2.1 go1.19

    tsh version

    Teleport v11.2.1 go1.19

To connect to Teleport, log in to your cluster using tsh, then use tctl remotely:

tsh login --proxy=teleport.example.com [email protected]
tctl status

Cluster teleport.example.com

Version 11.3.1

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.

To connect to Teleport, log in to your cluster using tsh, then use tctl remotely:

tsh login --proxy=myinstance.teleport.sh [email protected]
tctl status

Cluster myinstance.teleport.sh

Version 11.2.1

CA pin sha256:sha-hash-here

You must run subsequent tctl commands in this guide on your local machine.

  • A running instance of the Teleport SSH Service that you have registered with your Teleport cluster. For instructions on setting this up, see the Getting Started Guide. The SSH node must include a user you want to grant access to. In this guide, we will call the SSH node my-node and the user ci-user. Replace these with values appropriate to your setup.
  • A CircleCI project connected to a Git repository you can push to.

Step 1/4. Configure CircleCI

In order to configure the rules for which CircleCI workflows will be allowed to connect to your Teleport cluster, you must determine the ID of your CircleCI organization and create a CircleCI context.

Find your organization ID

Open CircleCI and navigate to "Organization settings" from the navbar. You should be presented with an interface titled "Overview" with a section called "Organization ID". Note this value down and substitute $ORGANIZATION_ID in configuration examples with this.

Create a context

CircleCI has an organization-level concept called contexts, which allow you to configure a series of secrets that should be exposed to a workflow job. You can configure CircleCI to control which actors are allowed to trigger jobs associated with a context.

The contexts that a workflow job has been assigned are also encoded in the identity token that CircleCI creates for the job. This makes them an ideal way for Teleport to determine which CircleCI jobs should be granted access to the Teleport cluster.

In this example, you will create a CircleCI context named teleport-access. You will then grant this context access to your Teleport cluster.

To create the CircleCI context, open up "Organization settings" in CircleCI and navigate to "Contexts". Click "Create Context" and provide teleport-access as the name of the context you wish to create. You may substitute this value for a string that makes more sense to your organization, but ensure in future steps of this guide that you replace teleport-access with your value.

Select the context you have just created. You will now be on a page that allows you to configure the context. To determine the ID of the context to use when configuring Teleport, locate the URL of the context settings page, which should have a format similar to the following:

https://app.circleci.com/settings/organization/github/gravitational/contexts/00000000-0000-0000-0000-000000000000

In this case, the context ID is: 00000000-0000-0000-0000-000000000000.

Note this value down and substitute $CONTEXT_ID in configuration examples with this.

Step 2/4. Create the join token for CircleCI

In order to allow your CircleCI 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.

Create a file named tokenconfig.yaml, ensuring that you replace $ORGANIZATION_ID and $CONTEXT_ID with the values from Step 1.

kind: token
version: v2
metadata:
  name: circleci-demo
  expires: "2100-01-01T00:00:00Z"
spec:
  roles: [Bot]
  join_method: circleci
  bot_name: circleci-demo
  circleci:
    organization_id: $ORGANIZATION_ID
    allow:
      - context_id: $CONTEXT_ID

Let's go over the token resource'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 year 2100.
  • 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 CircleCI, you will set this to to circleci.
  • spec.circleci.allow is used to set rules for what CircleCI runs will be able to authenticate by using the token.

Apply this to your Teleport cluster using tctl:

tctl create -f tokenconfig.yaml

Step 3/4. Create a Machine ID bot

With the join token for the CircleCI project 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 (such as a Single Sign-On solution).

For this guide, we are using the default access role and explicitly stating that the bot should have access to the ci-user login on hosts. In production environments, we recommend creating a custom role for your CI/CD workflow and ensuring that this role has no more permissions than is needed for the workflow to complete its tasks.

Use tctl to create the bot:

tctl bots add circleci-demo --roles=access --logins=ci-user --token=circleci-demo

Step 4/4. Configure a CircleCI workflow

With the token and bot now configured, you can now create a CircleCI workflow that can connect to your Teleport cluster.

Our example workflow will connect to an SSH node named my-node and write a line to a file that links back to the CI/CD run. This is a trivial example and could be replaced with pushing new configuration or binaries over SSH.

Open your Git repository and create a directory called .circleci. Then open a file called config.yml and insert the following configuration:

# See: https://circleci.com/docs/2.0/configuration-reference
version: 2.1
jobs:
  write-run-log:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run:
          name: "Install Teleport"
          command: |
            cd /tmp
            curl -O https://cdn.teleport.dev/teleport-11.3.1-linux-amd64-bin.tar.gz
            tar -xvf teleport-11.3.1-linux-amd64-bin.tar.gz
            sudo ./teleport/install
      - run:
          name: "Use Machine ID to access Teleport Node"
          command: |
            tbot start \
              --auth-server=tele.example.com:443 \
              --join-method=circleci --token=circleci-demo \
              --oneshot \
              --destination-dir=./certs \
              --data-dir=/tmp/tbot-data
            tsh \
              -i ./certs/identity \
              --proxy tele.example.com:443 \
              ssh [email protected] \
              "echo $CIRCLE_BUILD_URL >> ~/circle_run_log_demo"
workflows:
  write-run-log:
    jobs:
      - write-run-log:
          context:
            - teleport-access

Replace tele.example.com:443 with the public-facing address of your Teleport Proxy Service or cloud tenant (e.g. example.teleport.sh). Replace my-node with the name of the Teleport node that you wish to connect to and replace ci-user with the login you configured in Step 3.

Add, commit, and push this new configuration file to your repository.

Open CircleCI and check the status of the job, wait for it to complete and ensure that no errors are emitted.

SSH into my-node and confirm that a file has been created in ci-user's home directory named circle_run_log with a link to the build in CircleCI.

A note on security implications and risk

Once tbot start has been used in a job, all successive steps in that job will have access to the credentials that have been produced by tbot. Break your workflow down into multiple jobs to reduce the amount of steps that have access to these credentials.

Ensure that the role you assign to your CircleCI bot has access to only the resources in your Teleport cluster that your CI/CD needs to interact with.

Further steps

For more information about CircleCI itself, read their documentation.