Skip to content

Commit ba4489b

Browse files
[Fix] Do not specify --tenant flag when fetching managed identity access token from the CLI (#1021)
## Changes Addresses databricks/terraform-provider-databricks#3918. The Azure CLI's `az account get-access-token` command does not allow specifying `--tenant` flag if it is authenticated via the CLI. See hashicorp/go-azure-sdk#910 for context; this implementation mimics the work done there. ## Tests Unit tests ensure that all expected cases are treated as managed identities. Added an integration test to verify that this works on machines using MSI with the Azure CLI installed. - [ ] `make test` passing - [ ] `make fmt` applied - [ ] relevant integration tests applied --------- Co-authored-by: Renaud Hartert <[email protected]>
1 parent f624809 commit ba4489b

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

config/auth_azure_cli.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,34 @@ func (ts *azureCliTokenSource) Token() (*oauth2.Token, error) {
160160
}
161161

162162
func (ts *azureCliTokenSource) getTokenBytes() ([]byte, error) {
163+
// When fetching an access token from the CLI with a managed identity, the tenant ID should not be specified.
164+
// https://github.com/hashicorp/go-azure-sdk/pull/910/files demonstrates how to detect whether the CLI is authenticated
165+
// using a managed identity.
166+
accountRaw, err := runCommand(ts.ctx, "az", []string{"account", "show", "--output", "json"})
167+
if err != nil {
168+
return nil, fmt.Errorf("cannot get account info: %w", err)
169+
}
170+
var account struct {
171+
User struct {
172+
Name string `json:"name"`
173+
Type string `json:"type"`
174+
} `json:"user"`
175+
}
176+
if err := json.Unmarshal(accountRaw, &account); err != nil {
177+
return nil, fmt.Errorf("cannot unmarshal account info: %w", err)
178+
}
179+
isMsi := account.User.Type == "servicePrincipal" && (account.User.Name == "systemAssignedIdentity" || account.User.Name == "userAssignedIdentity")
180+
if !isMsi {
181+
return ts.getTokenBytesWithTenantId(ts.azureTenantId)
182+
}
183+
return ts.getTokenBytesWithTenantId("")
184+
}
185+
186+
func (ts *azureCliTokenSource) getTokenBytesWithTenantId(tenantId string) ([]byte, error) {
163187
args := []string{"account", "get-access-token", "--resource",
164188
ts.resource, "--output", "json"}
165-
if ts.azureTenantId != "" {
166-
args = append(args, "--tenant", ts.azureTenantId)
189+
if tenantId != "" {
190+
args = append(args, "--tenant", tenantId)
167191
}
168192
subscription := ts.getSubscription()
169193
if subscription != "" && ts.azureTenantId == "" {

config/auth_azure_cli_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,30 @@ func TestAzureCliCredentials_DoNotFetchIfTenantIdAlreadySet(t *testing.T) {
245245
assert.NoError(t, err)
246246
}
247247

248+
func TestAzureCliCredentials_DoNotSpecifyTenantIdWithMSI(t *testing.T) {
249+
cases := []struct {
250+
userName string
251+
}{
252+
{"systemAssignedIdentity"},
253+
{"userAssignedIdentity"},
254+
}
255+
for _, c := range cases {
256+
t.Run(c.userName, func(t *testing.T) {
257+
env.CleanupEnvironment(t)
258+
t.Setenv("PATH", testdataPath())
259+
t.Setenv("FAIL_IF_TENANT_ID_SET", "true")
260+
t.Setenv("AZ_USER_NAME", c.userName)
261+
t.Setenv("AZ_USER_TYPE", "servicePrincipal")
262+
aa := AzureCliCredentials{}
263+
_, err := aa.Configure(context.Background(), &Config{
264+
Host: "https://adb-xyz.c.azuredatabricks.net/",
265+
AzureTenantID: "123",
266+
})
267+
assert.NoError(t, err)
268+
})
269+
}
270+
}
271+
248272
// TODO: this test should rather be on sequencing
249273
// func TestConfigureWithAzureCLI_SP(t *testing.T) {
250274
// aa := DatabricksClient{

config/testdata/az

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
#!/bin/bash
22

3+
# If the arguments are "account show", return the account details.
4+
if [ "$1" == "account" ] && [ "$2" == "show" ]; then
5+
/bin/echo "{
6+
\"environmentName\": \"AzureCloud\",
7+
\"id\": \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",
8+
\"isDefault\": true,
9+
\"name\": \"Pay-As-You-Go\",
10+
\"state\": \"Enabled\",
11+
\"tenantId\": \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",
12+
\"user\": {
13+
\"name\": \"${AZ_USER_NAME:-testuser@databricks.com}\",
14+
\"type\": \"${AZ_USER_TYPE:-user}\"
15+
}
16+
}"
17+
exit 0
18+
fi
19+
320
if [ "yes" == "$FAIL" ]; then
421
>&2 /bin/echo "This is just a failing script."
522
exit 1
@@ -27,6 +44,16 @@ if [ -n "$COUNT" ]; then
2744
echo -n x >> "$COUNT"
2845
fi
2946

47+
# If FAIL_IF_TENANT_ID_SET is set & --tenant-id is passed, fail.
48+
if [ -n "$FAIL_IF_TENANT_ID_SET" ]; then
49+
for arg in "$@"; do
50+
if [[ "$arg" == "--tenant" ]]; then
51+
echo 1>&2 "ERROR: Tenant shouldn't be specified for managed identity account"
52+
exit 1
53+
fi
54+
done
55+
fi
56+
3057
# Macos
3158
EXP="$(/bin/date -v+${EXPIRE:=10S} +'%F %T' 2>/dev/null)"
3259
if [ -z "${EXP}" ]; then

0 commit comments

Comments
 (0)