Skip to main content

Configuring Workload Identity and Azure Federated Credentials

Design Partnership

We're actively looking for design partners to help us shape the future of Teleport Workload Identity and would love to hear your feedback.

Teleport Workload Identity issues flexible short-lived identities in JWT format. Azure Federated Credentials allows you to use these JWTs to authenticate to Azure services.

This can be useful in cases where a machine needs to securely authenticate with Azure services without the use of a long-lived credential. This is because the machine can authenticate with Teleport without using any shared secrets by using one of our delegated join methods.

In this guide, we'll configure Teleport Workload Identity and Azure to allow our workload to authenticate to the Azure Blob Storage and upload content to a container.

How it works

This implementation differs from using the Teleport Application Service to protect Azure APIs in a few ways:

  • Requests to Azure are not proxied through the Teleport Proxy Service, meaning reduced latency but also less visibility, as these requests will not be recorded in Teleport's audit log.
  • Workload Identity works with any Azure client, including the command-line tool but also their SDKs.
  • Using the Teleport Application Service to access Azure does not work with Machine ID and therefore cannot be used when a machine needs to authenticate with Azure.

Prerequisites

  • A running Teleport cluster version 16.4.8 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. For example:
    $ tsh login --proxy=teleport.example.com [email protected]
    $ tctl status
    # Cluster teleport.example.com
    # Version 16.4.8
    # 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.
  • tbot must already be installed and configured on the host where the workloads which need to access Teleport Workload Identity will run. For more information, see the deployment guides.
  • An Azure resource group and subscription you wish to grant the workload access to.
warning

Issuing JWT SVIDs with Teleport Workload Identity requires at least Teleport version 16.4.3.

Deciding on a SPIFFE ID structure

Within Teleport Workload Identity, all identities are represented using a SPIFFE ID. This is a URI that uniquely identifies the entity that the identity represents. The scheme is always spiffe://, and the host will be the name of your Teleport cluster. The structure of the path of this URI is up to you.

For the purposes of this guide, we will be granting access to Azure to the spiffe://example.teleport.sh/svc/example-service SPIFFE ID.

If you have already deployed Teleport Workload Identity, then you will already have a SPIFFE ID structure in place. If you have not, then you will need to decide on a structure for your SPIFFE IDs.

If you are only using Teleport Workload Identity with AWS OIDC Federation, you may structure your SPIFFE IDs so that they explicitly specify the Azure user-managed identity they are allowed to assume. However, it often makes more sense to name the workload or person that will use the SPIFFE ID. See the best practices guide for further advice.

Step 1/4. Configure Azure

To configure Azure to accept Workload Identity JWT SVIDs as authentication, you'll need to create an identity to represent that workload within Azure, configure that identity to accept JWT SVIDs issued by your Teleport Cluster as a federated credential, and then grant that identity the necessary permissions within Azure using a role assignment.

Create a user-managed identity

First, you'll create a user-managed identity to represent the workload within Azure.

  1. Browse to the "Managed Identities" section of the Azure Portal.
  2. Select "Create" to open the "Create User Assigned Managed Identity" form.
  3. Select your resource group and subscription.
  4. Enter a unique name for your identity that describes the workload it will represent. In our example, we will use "example-service".
  5. Select "Review + create".

You now need to record some key information about the created user-managed identity to be used in future steps.

Browse to the "Properties" section on the created user-managed identity and note down the "Client Id" and "Tenant Id", these values will both be UUIDs.

Create a federated credential

Next, you need to configure a federated credential for the user-managed identity. This will configure Azure to accept JWT SVIDs issued by your Teleport cluster as a form of authentication for this user-managed identity.

  1. Browse to your user-managed identity in the Azure Portal and select the "Federated credentials" page from the "Settings" section.
  2. Select "Add Credential" to open the "Add Federated Credential" form.
  3. Select "Other" for the "Federated credential scenario".
  4. Enter the address of your Teleport Proxy service followed by /workload-identity for the "Issuer URL", for example https://example.teleport.sh/workload-identity.
  5. Enter the SPIFFE ID you have decided on for the workload in the "Subject identifier" field. For example, spiffe://example.teleport.sh/svc/example-service. This will control which JWT SVIDs issued by Teleport Workload Identity will be accepted for this user-managed identity.
  6. Enter a unique, identifiable name for the federated credential. For example, example-teleport-sh-svc-example-service.
  7. Click "Add".

Create a storage account and container

For the purposes of this guide, you'll create a storage account and container for your workload to authenticate to. You can skip this step if you already have resources you wish to grant the workload access to.

First, create a storage account:

  1. Browse to the "Storage accounts" section of the Azure Portal and select the "Create" button to open the "Create a storage account" form.
  2. Select your resource group and subscription.
  3. Enter a unique, identifiable name for the storage account. Record this as you will need it later. In our examples we will use examplestorageaccount.
  4. Select a region and select "Azure Blob Storage" for the "Primary Service" field.
  5. Click "Create".

Now, you can create a storage container:

  1. Browse to the "Storage accounts" section of the Azure Portal and select the storage account you created.
  2. Browse to the "Containers" section beneath the "Data storage" section.
  3. Select "Add container" to open the "New container" form.
  4. Enter a unique, identifiable name for the container. Record this as you will need it later. In our examples we will use examplecontainer.

Create a role assignment

Finally, you need to grant the user-managed identity the necessary permissions for your workload to perform the actions it needs to within Azure.

When creating a role assignment in Azure, it can be scoped to different levels:

  • Subscription (to grant access to any resource within the subscription)
  • Resource Group (to grant access to any resource within the resource group)
  • Resource (to grant access to a specific resource)

For the purposes of this guide, we will grant the user-managed identity the Storage Blob Data Owner role with the scope of the storage account you have created.

  1. Browse to the "Storage accounts" section of the Azure Portal and select the storage account you created.
  2. Browse to "Access control (IAM)" in the sidebar, then select "Add" and "Add role assignment".
  3. Under "Role" select "Storage Blob Data Owner".
  4. Under "Members", for "Assign access to" select "Managed identity" and then press "Select members".
  5. For "Managed identity", select "User-assigned managed identity" and then search for and select the user-managed identity you created earlier.
  6. Click "Review + assign" and save your changes.

Step 2/4. Configure Teleport RBAC

Now we need to configure Teleport to allow a JWT to be issued containing the SPIFFE ID we have chosen.

Create role.yaml with the following content:

kind: role
version: v6
metadata:
name: my-workload-azure
spec:
allow:
spiffe:
- path: /svc/example-service

Replace:

  • my-workload-azure with a descriptive name for the role.
  • /svc/example-service with the path part of the SPIFFE ID you have chosen.

Apply this role to your Teleport cluster using tctl:

$ tctl create -f role.yaml

You now need to assign this role to the bot:

$ tctl bots update my-bot --add-roles my-workload-azure

Step 3/4. Issue Workload Identity JWTs

You'll now configure tbot to issue and renew the short-lived JWT SVIDs for your workload. It'll write the JWT as a file on disk, where you can then configure Azure clients and SDKs to read it.

Take your already deployed tbot service and configure it to issue SPIFFE SVIDs by adding the following to the tbot configuration file:

outputs:
- type: spiffe-svid
destination:
type: directory
path: /opt/workload-identity
svid:
path: /svc/example-service
jwts:
- audience: api://AzureADTokenExchange
file_name: azure-jwt

Replace:

  • /opt/workload-identity with the directory where you want the JWT to be written.
  • /svc/example-service with the SPIFFE ID you have chosen.

Restart your tbot service to apply the new configuration. You should see a file created at /opt/workload-identity/azure-jwt containing the JWT.

Step 4/4. Configure the Azure CLIs and SDKs

You can now use the issued JWT SVID to authenticate to Azure. How this is configured varies between the Azure CLI and Azure SDK.

Configuring Azure CLI

To use the JWT SVID to authenticate with the Azure CLI, you perform log-in specifying the JWT and the client and tenant ID of the user-managed identity you created. This performs an initial exchange of the JWT SVID for an Azure access token, which is then cached by the CLI until the access token expires.

Run the following, inserting the client and tenant id you recorded in the first step:

$ az login \ 
--federated-token $(cat /opt/workload-identity/azure-jwt) \
--service-principal \
-u <user-managed-identity-client-id> \
-t <user-managed-identity-tenant-id>

You should see a message indicating that this has succeeded.

You can now test this has succeeded by uploading a file to the Azure Blob Storage container:

$ echo "testing 1,2,3..." > test.txt
# Upload a test file. Replace the name of the account and container with those
# you selected earlier.
$ az storage blob upload \
--auth login \
--account-name examplestorageaccount \
--container-name examplecontainer \
--name test.txt \
--file ./test.txt
# Check that the file has been uploaded. Replace the name of teh account and
# container with those you selected earlier.
$ az storage blob list \
--auth login \
--output table \
--account-name examplestorageaccount \
--container-name examplecontainer

Configuring Azure SDKs

The Azure SDKs support a set of environment variables to configure them to use the federated credential for authentication with the issued JWT SVID:

  • AZURE_CLIENT_ID: The client ID of the user-managed identity.
  • AZURE_TENANT_ID: The tenant ID of the user-managed identity.
  • AZURE_FEDERATED_TOKEN_FILE: The path to the JWT SVID file, for example /opt/workload-identity/azure-jwt.

You can also explicitly configure the SDK to use the federated credential, this will vary language-to-language.

Next steps