rfd/0102-azure-node-join.md
Engineering: @jakule && @r0mant Product: @klizhentas && @xinding33 Security: @reedloden
Teleport nodes running on Azure virtual machines will be able to join a Teleport cluster without the need to share any secret token with the node. Instead, the node will present an attested data document and an access token generated from the instance metadata managed identity endpoint to confirm the subscription the VM is running in. With a configured Azure join token on the auth server, the node will be allowed to join the cluster based on its Azure subscription.
This is the Azure equivalent of EC2/IAM join as described in RFD 41.
This will make provisioning nodes on Azure simpler and arguably more secure. There is no need to configure static tokens, or to manage the provisioning and deployment of dynamic tokens.
In place of a join token, nodes will present a JWT access token and an attested
data document to the auth server, both of which will be fetched on the nodes
via instance metadata. The attested data request can include a user-specified
nonce which will also be signed. Like the custom headers in IAM join, the nonce
allows Teleport to issue a challenge (crypto random string of bytes) that the
node must include in the signed request. We can use gRPC bidirectional streams
to implement the following flow at a new RegisterWithAzureToken gRPC endpoint:
RegisterWithAzureToken request.RegisterUsingTokenRequest.RegisterWithAzureToken request and hasn't expired.xms_mirid claim.As with IAM join, the flow will occur within a single streaming gRPC request and only 1 attempt with a given challenge will be allowed, with a 1 minute timeout.
The Azure VM will need either a system- or user-assigned
managed identity
to be able to request an access token. The identity will need the
Microsoft.Compute/virtualMachines/read permission. If a VM has more than one
assigned identity, the identity to use must be specified in the join parameters.
When verifying the signature of attested data, Teleport should accept the following common names in certificates:
Additionally, Teleport will pin any needed intermediate certificates at build time, as it already does for EC2 join. More information on Azure certificate authorities can be found in the Azure documentation.
The existing provision token type can be extended to support Azure authentication, using new Azure-specific fields in the token rules section.
kind: token
version: v2
metadata:
name: example_azure_token
spec:
roles: [Node, Kube, Db]
azure:
allow:
# Subscription from which nodes can join. Required.
- azure_subscription: '22222222'
# Resource groups from which nodes can join. If empty or omitted, nodes
# from any resource group are allowed.
azure_resource_groups: ['rg1', 'rg2']
teleport.yaml on the nodes should be configured so that they will use the Azure join token:
teleport:
join_params:
token_name: 'example_azure_token'
method: azure
azure:
# client ID of the managed identity to use. Required if the VM has more
# than one assigned identity.
client_id: <client_id>
{
"encoding": "pkcs7",
"signature": "MIIEEgYJKoZIhvcNAQcCoIIEAzCCA/8CAQExDzANBgkqhkiG9w0BAQsFADCBugYJKoZIhvcNAQcBoIGsBIGpeyJub25jZSI6IjEyMzQ1NjY3NjYiLCJwbGFuIjp7Im5hbWUiOiIiLCJwcm9kdWN0IjoiIiwicHVibGlzaGVyIjoiIn0sInRpbWVTdGFtcCI6eyJjcmVhdGVkT24iOiIxMS8yMC8xOCAyMjowNzozOSAtMDAwMCIsImV4cGlyZXNPbiI6IjExLzIwLzE4IDIyOjA4OjI0IC0wMDAwIn0sInZtSWQiOiIifaCCAj8wggI7MIIBpKADAgECAhBnxW5Kh8dslEBA0E2mIBJ0MA0GCSqGSIb3DQEBBAUAMCsxKTAnBgNVBAMTIHRlc3RzdWJkb21haW4ubWV0YWRhdGEuYXp1cmUuY29tMB4XDTE4MTEyMDIxNTc1N1oXDTE4MTIyMDIxNTc1NlowKzEpMCcGA1UEAxMgdGVzdHN1YmRvbWFpbi5tZXRhZGF0YS5henVyZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAML/tBo86ENWPzmXZ0kPkX5dY5QZ150mA8lommszE71x2sCLonzv4/UWk4H+jMMWRRwIea2CuQ5RhdWAHvKq6if4okKNt66fxm+YTVz9z0CTfCLmLT+nsdfOAsG1xZppEapC0Cd9vD6NCKyE8aYI1pliaeOnFjG0WvMY04uWz2MdAgMBAAGjYDBeMFwGA1UdAQRVMFOAENnYkHLa04Ut4Mpt7TkJFfyhLTArMSkwJwYDVQQDEyB0ZXN0c3ViZG9tYWluLm1ldGFkYXRhLmF6dXJlLmNvbYIQZ8VuSofHbJRAQNBNpiASdDANBgkqhkiG9w0BAQQFAAOBgQCLSM6aX5Bs1KHCJp4VQtxZPzXF71rVKCocHy3N9PTJQ9Fpnd+bYw2vSpQHg/AiG82WuDFpPReJvr7Pa938mZqW9HUOGjQKK2FYDTg6fXD8pkPdyghlX5boGWAMMrf7bFkup+lsT+n2tRw2wbNknO1tQ0wICtqy2VqzWwLi45RBwTGB6DCB5QIBATA/MCsxKTAnBgNVBAMTIHRlc3RzdWJkb21haW4ubWV0YWRhdGEuYXp1cmUuY29tAhBnxW5Kh8dslEBA0E2mIBJ0MA0GCSqGSIb3DQEBCwUAMA0GCSqGSIb3DQEBAQUABIGAld1BM/yYIqqv8SDE4kjQo3Ul/IKAVR8ETKcve5BAdGSNkTUooUGVniTXeuvDj5NkmazOaKZp9fEtByqqPOyw/nlXaZgOO44HDGiPUJ90xVYmfeK6p9RpJBu6kiKhnnYTelUk5u75phe5ZbMZfBhuPhXmYAdjc7Nmw97nx8NnprQ="
}
Decoded contents of the attested data document:
{
"licenseType": "",
"nonce": "Yi09ymh-yIl4_zkmA6kIki4mDPpUlVxK",
"plan": {
"name": "",
"product": "",
"publisher": ""
},
"sku": "20_04-lts-gen2",
"subscriptionId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"timeStamp": {
"createdOn": "12/06/22 21:01:35 -0000",
"expiresOn": "12/07/22 03:01:35 -0000"
},
"vmId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
{
"aud": "https://management.azure.com/",
"iss": "https://sts.windows.net/ff882432-09b0-437b-bd22-ca13c0037ded/",
"iat": 1671237372,
"nbf": 1671237372,
"exp": 1671324072,
"aio": "...",
"appid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"appidacr": "2",
"idp": "https://sts.windows.net/ff882432-09b0-437b-bd22-ca13c0037ded/",
"idtyp": "app",
"oid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"rh": "...",
"sub": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"tid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"uti": "...",
"ver": "1.0",
"xms_mirid": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourcegroups/example_group/providers/Microsoft.Compute/virtualMachines/example_vm",
"xms_tcdt": "1434650756"
}