Skip to main content

Protect Azure CLIs with Teleport Application Access

You can use Teleport to manage access to CLI tools that interact with Azure's APIs. This lets you control access to your infrastructure's management APIs using the same RBAC system that you use to protect your infrastructure itself.

In this guide, you will:

  1. Create an Azure managed identity for user access and attach it your VM.
  2. Deploy a Teleport Application Service with an Azure app in your Teleport cluster.
  3. Assume the managed identity and run az commands via tsh.

How it works

The Teleport Application Service installed on an Azure VM uses managed identities to obtain authentication tokens from Azure. When a user authenticates to Teleport, they can assume one of the respective user-assigned managed identities to execute Azure CLI commands.

You can configure which Teleport users or roles have access to specific Azure identities, giving you control over who can obtain credentials for different levels of access to Azure CLIs.

The Teleport Application Service connects to the Teleport Proxy Service over a reverse tunnel, so you can run the Application Service in a private network and prevent unauthorized access to your organization's Azure identities.

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

    Visit Installation for instructions on downloading tctl and tsh.

  • The az CLI tool installed on your workstation. Teleport's tsh client uses the az binary to execute commands. See the Azure documentation for how to install the az CLI on your operating system.

  • An Azure VM where you will run the Teleport Application Service. The Azure VM must be running a Linux distribution.

    Azure Kubernetes Service (AKS)

    Note that this guide is also applicable to Azure Kubernetes Service (AKS) deployment with Microsoft Entra pod-managed identities enabled. However, the pod-managed identities feature will be deprecated in September 2024.

    For running Teleport Application Service in AKS with Microsoft Entra Workload ID, see Azure CLI Access on AKS with Workload ID.

  • The ability to create a user-assigned Azure managed identity and attach it to your VM. Azure requires three role assignments in your Azure account in order to do this: Managed Identity Contributor, Managed Identity Operator, and Virtual Machine Contributor.

    Using existing identities

    In this guide, we will create a user-assigned managed identity to demonstrate Azure CLI access with Teleport.

    If you have another identity you would like Azure CLI users to assume via Teleport, you can use that instead. In this case, you will not need the Managed Identity Contributor role assignment.

  • 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 --user=email@example.com
    $ tctl status
    # Cluster teleport.example.com
    # Version 17.0.0-dev
    # 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.

Step 1/4. Grant an identity to your VM

In this step, we will create an Azure managed identity and assign it to your Azure VM. The identity we will create will be called teleport-azure, and will have permissions to view resources in your Azure account.

You can enable Teleport to grant access to Azure CLIs under any Azure identity. If you have another one you intend to use, you can skip the creation of a new identity.

Create an Azure managed identity

Visit the Managed Identities view in Azure Portal.

Click Create.

Under Subscription, Resource group, and Region, choose the ones that your VM belongs to.

In the Name field, enter teleport-azure.

Click Review + create, then Create.

Once creation finishes, click Go to resource. On the page for the new identity, click JSON View. At the top of the right sidebar, you will see a field called Resource ID with a value resembling the following:

/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/teleport-azure

Copy the URI of this identity so you can use it later in this guide.

Allow the teleport-azure identity to view resources

Once you create an Azure identity, authorize it to access resources in your account. In this case, we will authorize your new Azure identity to view resources in its resource group.

Enter the name of your Azure resource group in the Azure Portal search box and visit the page for that resource group. On the left navigation sidebar, click the Access control (IAM) tab. In the row of buttons at the top of the Access control (IAM) panel, click Add > Add role assignment.

Within the Add role assignment screen, click Reader, a built-in role with view-only access to resources.

Scroll to the bottom of the screen and click Next.

Within the Members tab, in the Assign access to field, choose Managed identity. Click Select members.

On the right sidebar, find the Managed identity dropdown menu and select User-assigned managed identity. Choose the teleport-azure identity you created earlier.

Click Select, then Review + assign.

Verify that your Role is "Reader", the Scope matches your chosen resource group, and the Members field includes the teleport-azure managed identity you created earlier.

Click Review + assign again.

Attach an identity to your Azure VM

Now that you have created a managed identity and assigned it a role, attach the identity to your Azure VM so the Teleport Application Service can assume the identity in order to proxy Azure CLI traffic.

In the Virtual machines view of Azure Portal, click on the name of the VM you are using to host the Teleport Application Service.

On the right side panel, click the Identity tab, then within the Identity view, click the User assigned tab. Click +Add, then select the teleport-azure identity. Click Add.

Navigate back to Identity tab in the page for your Azure VM. You should see the new identity listed in the User assigned sub-tab:

Step 2/4. Deploy the Teleport Application Service

In this step, you will run the Teleport Application Service on the Azure VM you assigned the teleport-azure identity to.

Get a join token

Establish trust between your Teleport cluster and your new Application Service instance by creating a join token:

$ tctl tokens add --type=app --ttl=1h --format=text
abcd123-insecure-do-not-use-this

On the host where you will install the Teleport Application Service, create a file called /tmp/token that consists only of your token:

$ echo join-token | sudo tee /tmp/token

Install the Teleport Application Service

Run the following commands on the host where you will install the Teleport Application Service:

Install Teleport on your Linux server:

  1. Assign edition to one of the following, depending on your Teleport edition:

    EditionValue
    Teleport Enterprise Cloudcloud
    Teleport Enterprise (Self-Hosted)enterprise
    Teleport Community Editionoss
  2. Get the version of Teleport to install. If you have automatic agent updates enabled in your cluster, query the latest Teleport version that is compatible with the updater:

    $ TELEPORT_DOMAIN=example.teleport.com
    $ TELEPORT_VERSION="$(curl https://$TELEPORT_DOMAIN/v1/webapi/automaticupgrades/channel/default/version | sed 's/v//')"

    Otherwise, get the version of your Teleport cluster:

    $ TELEPORT_DOMAIN=example.teleport.com
    $ TELEPORT_VERSION="$(curl https://$TELEPORT_DOMAIN/v1/webapi/ping | jq -r '.server_version')"
  3. Install Teleport on your Linux server:

    $ curl https://cdn.teleport.dev/install-v15.4.11.sh | bash -s ${TELEPORT_VERSION} edition

    The installation script detects the package manager on your Linux server and uses it to install Teleport binaries. To customize your installation, learn about the Teleport package repositories in the installation guide.

Configure the Teleport Application Service

On the host where you will run the Teleport Application Service, create a file at /etc/teleport.yaml with the following content:

version: v3
teleport:
join_params:
token_name: "/tmp/token"
method: token
proxy_server: "teleport.example.com:443"
auth_service:
enabled: off
proxy_service:
enabled: off
ssh_service:
enabled: off
app_service:
enabled: true
apps:
- name: azure-cli
cloud: Azure

Edit /etc/teleport.yaml to replace teleport.example.com:443 with the host and port of your Teleport Proxy Service or Teleport Cloud tenant, e.g., mytenant.teleport.sh:443.

The app_service field configures the Teleport Application Service. Each item within app_service.apps is an application configuration.

In this example, we have enabled Azure CLI access by setting cloud to Azure. With this setting configured, the Application Service will proxy user commands from Azure CLIs by requesting access to Azure's APIs under the user's chosen identity, which works as long as the identity is one of the ones attached to the Application Service host.

Run the Teleport Application Service

Configure the Teleport Application Service to start automatically when the host boots up by creating a systemd service for it. The instructions depend on how you installed the Teleport Application Service.

On the host where you will run the Teleport Application Service, enable and start Teleport:

$ sudo systemctl enable teleport
$ sudo systemctl start teleport

You can check the status of the Teleport Application Service with systemctl status teleport and view its logs with journalctl -fu teleport.

Step 3/4. Enable your user to access Azure CLIs

The next step is to authorize your Teleport user to assume an Azure identity and execute Azure CLI commands via Teleport. You will protect access to this identity using Teleport's RBAC system, where a user's roles determine which Azure managed identities (if any) they can access.

There are two approaches you can take to authorize users to access Azure identities.

ApproachDescriptionSupported User Types
DynamicA Teleport role includes a template variable that grants a user access to all Azure identities assigned directly to them.Local users, OIDC, SAML
StaticA Teleport role explicitly specifies the Azure identities a user is allowed to assume.Local users, OIDC, SAML, GitHub
tip

We recommend using the dynamic approach, since it scales well as you add Azure identities to your account. If you have configured a Teleport Community Edition cluster to authenticate users using GitHub SSO, you must use the static approach, as OAuth-based GitHub applications do not support custom claims.

Create a file called azure-cli-access.yaml with the following content:

kind: role
version: v5
metadata:
name: azure-cli-access
spec:
allow:
app_labels:
'*': '*'
azure_identities:
- '{{internal.azure_identities}}'

When a user with the azure-cli-access role authenticates to an Azure CLI via Teleport, the Teleport Auth Service populates the {{internal.azure_identities}} template variable with any Azure identities you have assigned to the user.

Assign the teleport-azure identity to your Teleport user by running the following command, pasting in the URI of the Azure identity you copied earlier as the value of --set-azure-identities:

$ tctl users update teleport-user \
--set-azure-identities azure-identity-uri

This command uses the --set-azure-identities flag to add Azure identities to a user. You can assign --set-azure-identities to multiple identity URIs, separated by commas.

The identity URIs are Azure resource IDs in the following format:

/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/RESOURCE_GROUP_NAME/providers/Microsoft.ManagedIdentity/userAssignedIdentities/IDENTITY_NAME

Create the role:

$ tctl create -f azure-cli-access.yaml
Denying access to Azure identities

You can define a Teleport role that denies a user access to one or more Azure identities. To do so, assign values to the azure_identities field within the spec.deny section of a role resource.

For example, this role denies the user access to all Azure identities:

kind: role
version: v5
metadata:
name: "no-azure-identities"
spec:
allow:
app_labels:
'*': '*'
deny:
azure_identities:
- '*'

The no-azure-identities role enables the user to access all registered applications, but makes use of the wildcard character (*) within the deny.azure_identities field to prevent the user from assuming any Azure identity.

Unlike values of allow.azure_identities, values of deny.azure_identities can include wildcard expressions in addition to the URIs of specific Azure identities.

The Teleport Auth Service gives deny rules precedence over allow rules when evaluating a user's roles.

Assign the azure-cli-access role to your Teleport user by running the appropriate commands for your authentication provider:

  1. Retrieve your local user's roles as a comma-separated list:

    $ ROLES=$(tsh status -f json | jq -r '.active.roles | join(",")')
  2. Edit your local user to add the new role:

    $ tctl users update $(tsh status -f json | jq -r '.active.username') \
    --set-roles "${ROLES?},azure-cli-access"
  3. Sign out of the Teleport cluster and sign in again to assume the new role.

Step 4/4. Use Azure CLIs with Teleport

Now that you have authorized your Teleport user to assume the teleport-azure identity, you can use Teleport to authenticate to Azure's APIs and execute commands against it via the az CLI.

List your Azure CLI application

Verify that your Teleport user can see the azure-cli application you registered earlier:

$ tsh apps ls
Application Description Type Public Address Labels
----------- ----------- ---- ------------------------------ -------------------
azure-cli HTTP azure-cli.teleport.example.com teleport.dev/origin

Log in to use an Azure CLI

Log in to the application, specifying that you would like to assume the teleport-azure identity:

$ tsh apps login azure-cli --azure-identity teleport-azure

This command validates the value of the --azure-identity flag against the ones the user is authorized to assume. The value of the flag can either be the full URI of the identity (e.g., the URI you copied earlier in this guide) or the name of the identity, e.g., teleport-azure.

A user can omit the --azure-identity flag if they are only authorized to access a single Azure identity, but otherwise not including the --azure-identity flag will result in an error.

If the command succeeds, you will see information about the user's chosen Azure identity similar to the following:

[
{
"environmentName": "AzureCloud",
"homeTenantId": "00000000-0000-0000-0000-000000000000",
"id": "00000000-0000-0000-0000-000000000000",
"isDefault": true,
"managedByTenants": [],
"name": "Microsoft Azure Sponsorship",
"state": "Enabled",
"tenantId": "00000000-0000-0000-0000-000000000000",
"user": {
"assignedIdentityInfo": "MSIResource-/subscriptions/0000000000000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/teleport-azure",
"name": "userAssignedIdentity",
"type": "servicePrincipal"
}
}
]

Logged into Azure app "azure-cli".
Your identity: /subscriptions/0000000000000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/teleport-azure
Example Azure CLI command: tsh az vm list

Execute Azure CLI commands

At this point, you can run az commands using the Teleport Application Service by prefixing them with tsh. To list VMs running in your Azure resource group, for example, run the following command:

$ tsh az vm list
tip

If you're not seeing the expected VMs at this point, double-check that your Azure managed identity is assigned the "Reader" role at the scope of your resource group.

Use Azure CLI applications without tsh

In addition to running az commands via tsh, you can grant secure access to any CLI application that executes commands against Azure's APIs.

To do this, use tsh to start a local proxy that forwards traffic from your CLI application to the Teleport Application Service. The Application Service uses an Azure managed identity to fetch an authentication token from Azure, which your CLI application uses to authenticate requests to Azure's APIs.

To start the local proxy, run the following tsh command:

$ tsh proxy azure 
tip

The command tsh proxy az is an alias for tsh proxy azure.

The command will print the address of the local proxy server along with export commands for assigning environment variables. Azure CLI applications read these variables in order to request an authentication token for Azure's APIs:

Started Azure proxy on http://127.0.0.1:54321.
To avoid port randomization, you can choose the listening port using the --port flag.

Use the following credentials and HTTPS proxy setting to connect to the proxy:

export AZURE_CONFIG_DIR=/Users/myuser/.tsh/azure/my.teleport.cluster/azure
export HTTPS_PROXY=http://127.0.0.1:54321
export HTTP_PROXY=http://127.0.0.1:54321
export MSI_ENDPOINT=https://azure-msi.teleport.dev/123456789abcdef01234
export REQUESTS_CA_BUNDLE=/Users/myuser/.tsh/keys/teleport.example.com/myuser-app/teleport.example.com/azure-cli-localca.pem
warning

tsh proxy azure runs the local proxy in the foreground, so don't interrupt the process or exit the terminal where you ran the command until you're ready to close the local proxy.

Copy the export commands and paste them into a second terminal. In that terminal, you can now run your Azure CLI application of choice. For example, you can run the following command to list Azure VMs:

$ az vm list

Since the az CLI requests an authentication token using the teleport-azure identity you created earlier, and that identity is authorized to view resources in your resource group, the az vm list command will only list VMs in that resource group.

info

When you run an az command via tsh az, tsh starts the local proxy in the background and uses it to execute the command.

Next steps