Databricks.API.PowerShell icon indicating copy to clipboard operation
Databricks.API.PowerShell copied to clipboard

Add a function to create new token without having a token

Open saldroubi opened this issue 3 years ago • 8 comments

Hello,

For Azure, sometimes you want to manage a workspace by creating a token programmatically to use in Set-DatabricksEnvironment -AccessToken $tokenObj.token_value -ApiRootUrl $apiUrl

In Azure, there is a way you can do that if you have the write permissions. I wrote the function below New-DBRApiToken which can be used to create a token that can be used in Set-DatabricksEnviornment.

Also, you can get the workspace url programmatically if you know the workspace name and the resource group name. See function below called Get-WorkspaceHostname

Does it make sense to add these to your module or some variation of these functions?

Thank you

Function New-DBRApiToken { <# .SYNOPSIS Create and return a token. This call returns the error QUOTA_EXCEEDED if the caller exceeds the token quota, which is 600. .DESCRIPTION Create and return a token. This call returns the error QUOTA_EXCEEDED if the caller exceeds the token quota, which is 600. Official API Documentation: https://docs.databricks.com/api/latest/tokens.html#create .PARAMETER LifetimeSeconds The lifetime of the token, in seconds. If no lifetime is specified, the token remains valid for 14400 seconds (30 hours) to create an indefinite token pass -1 .PARAMETER Comment Optional description to attach to the token. Default value is "Generated for workspace managment" .EXAMPLE Add-DatabricksApiToken -LifetimeSeconds 360 -Comment "MyComment #>

[CmdletBinding()] Param ( [Parameter(Mandatory = $True)][string]$ResourceGroupName, [Parameter(Mandatory = $True)][string]$WorkspaceName, [Parameter(Mandatory = $False)][long] $LifetimeSeconds = 1800, [Parameter(Mandatory = $False)][string] $Comment = "Generated for workspace management" )

# Code based on these References:
#   https://docs.microsoft.com/en-us/azure/databricks/dev-tools/api/latest/aad/service-prin-aad-token
#   https://cloudarchitected.com/2020/01/using-azure-ad-with-the-azure-databricks-api/

#$tenantID=    (Get-AzContext).Tenant.id
$workspaceID =  Get-AzResource -ResourceGroupName $ResourceGroupName | Where-Object  {$_.ResourceType -eq "Microsoft.Databricks/workspaces"} | Select-Object -ExpandProperty ResourceID

#Get a token for the global Databricks application.
$DBRGlobalUrl = "2ff814a6-3304-4ab8-85cb-cd0e6f879c1d"
$tokenObj = Get-AzAccessToken -ResourceUrl $DBRGlobalUrl
$DBRtoken = $tokenObj.Token

# Get a token for the Azure management API
$tokenObj = Get-AzAccessToken -ResourceUrl "https://management.core.windows.net"
$AMAtoken = $tokenObj.Token

# Create token DBR url
$url = "https://" + (Get-WorkspaceHostname -WorkspaceName $WorkspaceName -ResourceGroupName $ResourceGroupName) + "/api/2.0/token/create"

# set header and body for rest api call
$h = @{
    Authorization= "Bearer $($DBRtoken)"
    'X-Databricks-Azure-SP-Managment-Token' = "$($AMAtoken)"
    'X-Databricks-Azure-Workspace-Resource-Id' = "$($workspaceID)"
 }
$body = @{
    lifetime_seconds = $LifetimeSeconds 
    comment = $Comment
}
$resultObj = Invoke-RestMethod -Method Post -Headers $H -Body ($body | ConvertTo-Json -depth 20) -Uri $url
return $resultObj

}

<# .SYNOPSIS Returns the hostname for a specified databricks workspace. .EXAMPLE PS C:> Get-WorkspaceHostname -WorkspaceName "bricks-workspace-dataengineering" -ResourceGroup "rg-workspace-dataengineering" .OUTPUTS The workspace hostname #> function Get-WorkspaceHostname { [CmdletBinding()] [OutputType([string])] param ( # Databricks workspace name [Parameter(Mandatory)][string]$WorkspaceName, # Resource group name [Parameter(Mandatory)][string]$ResourceGroupName )

$workspaceResource = Get-AzResource `
    -ResourceType "Microsoft.Databricks/workspaces" `
    -Name $WorkspaceName  `
    -ResourceGroupName $ResourceGroupName `
    -ExpandProperties

return $workspaceResource.Properties.workspaceUrl

}

saldroubi avatar May 10 '22 16:05 saldroubi

Hi @saldroubi,

you can already use a user account or a service principal to authenticate without a Personal Access Token (PAT) - see https://github.com/gbrueckl/Databricks.API.PowerShell#azure-active-directory-aad-usernamepassword

instead of authenticating using Connect-AzAccount you would simply pass the same/similar parameters directly to Set-DatabricksEnvironment

The part of getting the URL programmatically is nice but introduces a dependency to the Az module which I definitely do not want as this module is supposed to also work with Databricks on AWS and GCP

gbrueckl avatar May 10 '22 18:05 gbrueckl

I just published v1.9.9.11 which introduces a new switch -UsingAzContext which in combination with -AzureResourceID allows you to derive all settings from an already authenticated Az module for details see https://github.com/gbrueckl/Databricks.API.PowerShell#azure-az-module-integration

gbrueckl avatar May 10 '22 20:05 gbrueckl

I just installed the v1.9.9.11 version but that switch Is missing. Here is the error I get when I run it.

Set-DatabricksEnvironment -UsingAzContext -AzureResourceID $azureResourceId Set-DatabricksEnvironment: Cannot bind positional parameters because no names were given.

When I tab after the "-" I get these possible parameters. None of which is UsingAzContext Set-DatabricksEnvironment -
ApiRootUrl OrgID JobsAPIVersion ErrorVariable
AccessToken SubscriptionID AzureActiveDirectoryAuthorityUrl WarningVariable
UsingDatabricksCLIAuthentication ResourceGroupName AzureActiveDirectoryServiceEndpointResourceId InformationVariable
Credential WorkspaceName Verbose OutVariable
UsingAzureDevOpsServiceConnection ServicePrincipal Debug OutBuffer
ClientID DynamicParameterCacheTimeout ErrorAction PipelineVariable
TenantID ApiCallRetryCount WarningAction
AzureResourceID ApiCallRetryWait InformationAction

Thank you

saldroubi avatar May 11 '22 18:05 saldroubi

it is definitely there: image make sure that you do not have any other parameters set already which do not belong to the same parameterset as this would hide the parameter

gbrueckl avatar May 12 '22 06:05 gbrueckl

Hi Gerhard,

Honestly, I am not sure why it was not working and I had version 1.9.9.1 installed.  I uninstalled it and re-installed and I see the parameter now.  Thank you very much. This works great!

One question, so you are not generating a token to setup the environment but rather using the existing az account token? Are you then this same az token to pass to Databricks as the bearer token in the REST API request? If so, why will this token work since it is not a token generated by Databricks?

I am finding the Azure security model a bit confusing with all these different tokens, some are AAD and some are Databricks. Is there a good reference to understand this well.

Thank you so much for this module. It is very helpful. I am hope I am doing my part by giving good feedback.

Sincerely, Sam Al-Droubi

saldroubi avatar May 12 '22 14:05 saldroubi

so there are two ways how you can interact with the DAtabricks REST API on Azure:

  • Personal Access Token (PAT)
  • Azure AD token (usernam/password or service principal)

either of them can be used for any call you make to the Databricks REST API - so you do not necessarily need PATs anymore but can only use AAD tokens

for the DatabricksPS module the only difference is how you call the Set-DatabricksEnvironment cmdlet, all other cmdlets just work the very same way

gbrueckl avatar May 12 '22 16:05 gbrueckl

Thank you Gerhard,

I understand the the personal Access Token (PAT). That is the one I can generate from the Databricks UI. But am confused about the username/password. Using

Set-DatabricksEnvironment -UsingAzContext -AzureResourceID $azureResourceId

I am not passing a username/password in this call and yet I am able to use functions like Get-DatabricksCluster. That is why I am confused. I hope you can explain this to me?

saldroubi avatar May 12 '22 16:05 saldroubi

In order to use -UsingAzContext you must have run Connect-AzAccount first with a username/pw The module then basically uses that information to generate a new AAD token for the Databricks API calls for you

Get Outlook for Androidhttps://aka.ms/AAb9ysg


From: saldroubi @.> Sent: Thursday, May 12, 2022 6:31:18 PM To: gbrueckl/Databricks.API.PowerShell @.> Cc: Gerhard Brueckl @.>; Comment @.> Subject: Re: [gbrueckl/Databricks.API.PowerShell] Add a function to create new token without having a token (Issue #54)

Thank you Gerhard,

I understand the the personal Access Token (PAT). That is the one I can generate from the Databricks UI. But am confused about the username/password. Using

Set-DatabricksEnvironment -UsingAzContext -AzureResourceID $azureResourceId

I am not passing a username/password in this call and yet I am able to use functions like Get-DatabricksCluster. That is why I am confused. I hope you can explain this to me?

— Reply to this email directly, view it on GitHubhttps://github.com/gbrueckl/Databricks.API.PowerShell/issues/54#issuecomment-1125198583, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AC2VO4UWTMINQUXR76P2HATVJUW5NANCNFSM5VSEDV3Q. You are receiving this because you commented.Message ID: @.***>

gbrueckl avatar May 12 '22 16:05 gbrueckl

This feature works. Thank you for adding it.

saldroubi avatar Sep 19 '22 22:09 saldroubi