{"id":39934,"date":"2020-11-12T00:36:56","date_gmt":"2020-11-12T07:36:56","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/premier-developer\/?p=39934"},"modified":"2020-11-09T11:08:51","modified_gmt":"2020-11-09T18:08:51","slug":"generate-a-service-bus-sas-token-and-manage-token-renewal-using-azure-runbooks","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/generate-a-service-bus-sas-token-and-manage-token-renewal-using-azure-runbooks\/","title":{"rendered":"Generate a Service Bus SAS Token and Manage Token renewal using Azure Runbooks"},"content":{"rendered":"<p><a href=\"https:\/\/www.linkedin.com\/in\/rakhi-guha-3930aa65\/\">Rakhi Guha<\/a> demonstrates how to use PowerShell and Azure Runbooks to automate Service Bus SAS Tokens.<\/p>\n<hr \/>\n<p>This article provide a detailed walk-through of<\/p>\n<ol>\n<li>Generating an Azure Service Bus token using PowerShell<\/li>\n<li>Using an Azure Runbook for the token generation and renewal process<\/li>\n<li>Steps to incorporate a Runbook with a CI\/CD pipeline to automate and manage the process.<\/li>\n<\/ol>\n<p><strong>The following code can be used to generate the SAS Token for Service Bus<\/strong><\/p>\n<pre class=\"prettyprint\">[Reflection.Assembly]::LoadWithPartialName(\"System.Web\")| out-null\r\n$URI=\"&lt;eventhubnamespace&gt;.servicebus.windows.net\"\r\n$Access_Policy_Name=\"&lt;PolicyName&gt;\"\r\n$Access_Policy_Key=\"&lt;Primary Access Name&gt;\"\r\n##Token expires now+7,776,000(3 month)\r\n$Expires=([DateTimeOffset]::Now.ToUnixTimeSeconds())+7776000\r\n$SignatureString=[System.Web.HttpUtility]::UrlEncode($URI)+ \"`n\" + [string]$Expires\r\n$HMAC = New-Object System.Security.Cryptography.HMACSHA256\r\n$HMAC.key = [Text.Encoding]::ASCII.GetBytes($Access_Policy_Key)\r\n$Signature = $HMAC.ComputeHash([Text.Encoding]::ASCII.GetBytes($SignatureString))\r\n$Signature = [Convert]::ToBase64String($Signature)\r\n$SASToken = \"SharedAccessSignature sr=\" + [System.Web.HttpUtility]::UrlEncode($URI) + \"&amp;sig=\" + [System.Web.HttpUtility]::UrlEncode($Signature) + \"&amp;se=\" + $Expires + \"&amp;skn=\" + $Access_Policy_Name\r\n$SASToken\r\n<\/pre>\n<p>We will be required to update the placeholder with appropriate values, specific to a use case.<\/p>\n<p>The line below sets the generated token in AKV secrets for secured communication. Any application requires to use the AKV secrets to get the token and eventually use the same for accessing the service bus.<\/p>\n<pre class=\"prettyprint\">Set-AzureKeyVaultSecret\u00a0-VaultName\u00a0'&lt;AKVNAME&gt;'\u00a0-Name\u00a0'&lt;SECRETNAME&gt;'\u00a0-SecretValue\u00a0$Secret<\/pre>\n<p>With the above code, the renewal of a SAS token will be required to re-execute the code once the token is expired in order to ensure the AKV contains the valid SAS token. In order to automate the entire process we can build up a process as described below<\/p>\n<ol>\n<li>Develop a run book with the below code.\n<pre class=\"prettyprint\">[Reflection.Assembly]::LoadWithPartialName(\"System.Web\")| out-null\r\n$serviceBusNameSpace=Get-AutomationVariable -Name 'ServiceBusNameSpace'\r\n$serviceBusAccessPolicyName=Get-AutomationVariable -Name 'ServiceBusAccessPolicyName'\r\n$serviceBusAccessPolicyKey=Get-AutomationVariable -Name 'ServiceBusAccessPolicyKey'\r\n$akvName=Get-AutomationVariable -Name 'AKVName'\r\n$sasTokenSecretName=Get-AutomationVariable -Name 'SASTokenSecretName'\r\n\r\n$URI=$serviceBusNameSpace+\".servicebus.windows.net\"\r\nwrite-host 'Generate SAS token for 3 month'\r\n#Token expires now+7,776,000(3 month)\r\n\r\n$Expires=([DateTimeOffset]::Now.ToUnixTimeSeconds())+7776000\r\n$SignatureString=[System.Web.HttpUtility]::UrlEncode($URI)+ \"`n\" + [string]$Expires\r\n$HMAC = New-Object System.Security.Cryptography.HMACSHA256\r\n$HMAC.key = [Text.Encoding]::ASCII.GetBytes($serviceBusAccessPolicyKey)\r\n$Expires\r\n$Signature = $HMAC.ComputeHash([Text.Encoding]::ASCII.GetBytes($SignatureString))\r\n$Signature = [Convert]::ToBase64String($Signature)\r\n$SASToken = \"SharedAccessSignature sr=\" + [System.Web.HttpUtility]::UrlEncode($URI) + \"&amp;sig=\" + [System.Web.HttpUtility]::UrlEncode($Signature) + \"&amp;se=\" + $Expires + \"&amp;skn=\" + $serviceBusAccessPolicyName\r\n$SASToken\r\n$SecretToken = ConvertTo-SecureString -String $SASToken -AsPlainText -Force\r\n\r\n$connectionName = \"AzureRunAsConnection\"\r\ntry\r\n{\r\n    # Get the connection \"AzureRunAsConnection \"\r\n    $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName         \r\n\r\n    \"Logging in to Azure...\"\r\n    Add-AzureRmAccount `\r\n        -ServicePrincipal `\r\n        -TenantId $servicePrincipalConnection.TenantId `\r\n        -ApplicationId $servicePrincipalConnection.ApplicationId `\r\n        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint \r\n}\r\ncatch {\r\n    if (!$servicePrincipalConnection)\r\n    {\r\n        $ErrorMessage = \"Connection $connectionName not found.\"\r\n        throw $ErrorMessage\r\n    } else{\r\n        Write-Error -Message $_.Exception\r\n        throw $_.Exception\r\n    }\r\n}\r\nwrite-host 'Update SAS token in AKV'\r\nSet-AzureKeyVaultSecret -VaultName $akvName -Name $sasTokenSecretName -SecretValue $SecretToken\r\nwrite-host 'Execution completed'\r\n<\/pre>\n<\/li>\n<li>Deploy the runbook integrated with the CI\/CD pipeline. In a CI pipeline package, the PowerShell script is described above. Once the build is generated with the package artifacts, follow the below steps\n<ol style=\"list-style-type: lower-alpha;\">\n<li>Create a CD pipeline and add an azure PowerShell task<img decoding=\"async\" width=\"748\" height=\"84\" class=\"wp-image-39935\" style=\"font-size: 1rem;\" src=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image.png\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image.png 748w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image-300x34.png 300w\" sizes=\"(max-width: 748px) 100vw, 748px\" \/><\/li>\n<li>In inline scripting option provide the following script.\n<pre class=\"prettyprint\">$serviceBusNamespaceKey=Get-AzureRmServiceBusKey -Namespace $(ServiceBusNameSpace)  -AuthorizationRuleName $(ServiceBusAccessPolicyName) -ResourceGroup $(PlantConnectorRG)\r\n$serviceBusNamespaceKey.PrimaryKey\r\n$SecretToken = ConvertTo-SecureString -String $serviceBusNamespaceKey.PrimaryKey -AsPlainText -Force\r\nSet-AzureKeyVaultSecret -VaultName $(KeyVaultName) -Name 'ServiceBusAccessPolicyKey' -SecretValue $SecretToken\r\n\r\n\r\nInstall-Module AzureRM.Automation -Scope CurrentUser -AllowClobber -Force\r\n\r\nImport-AzureRMAutomationRunbook -Name 'RenewSASToken' -Path &lt;Path of the Runbook PS script from build package&gt;  -ResourceGroupName $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Type PowerShell -Force -Published\r\ntry{\r\n $alreadyPresentVar = Get-AzureRmAutomationVariable -ResourceGroupName $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'ServiceBusNameSpace' -ErrorAction Stop\r\n Set-AzureRmAutomationVariable -ResourceGroupName  $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'ServiceBusNameSpace' -Value $(ServiceBusNameSpace) -Encrypted $false\r\n\r\n}\r\ncatch{\r\nNew-AzureRmAutomationVariable -ResourceGroupName  $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'ServiceBusNameSpace' -Value $(ServiceBusNameSpace) -Encrypted $false\r\n}\r\ntry{\r\n $alreadyPresentVar = Get-AzureRmAutomationVariable -ResourceGroupName $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'ServiceBusAccessPolicyName' -ErrorAction Stop\r\n Set-AzureRmAutomationVariable -ResourceGroupName  $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'ServiceBusAccessPolicyName' -Value $(ServiceBusAccessPolicyName) -Encrypted $false\r\n\r\n}\r\ncatch{\r\nNew-AzureRmAutomationVariable -ResourceGroupName  $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'ServiceBusAccessPolicyName' -Value $(ServiceBusAccessPolicyName) -Encrypted $false\r\n}\r\n\r\ntry{\r\n $alreadyPresentVar = Get-AzureRmAutomationVariable -ResourceGroupName $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'SASTokenSecretName' -ErrorAction Stop\r\n Set-AzureRmAutomationVariable -ResourceGroupName  $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'SASTokenSecretName' -Value $(SASTokenSecretName) -Encrypted $false\r\n\r\n}\r\ncatch{\r\nNew-AzureRmAutomationVariable -ResourceGroupName  $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'SASTokenSecretName' -Value $(SASTokenSecretName) -Encrypted $false\r\n}\r\ntry{\r\n $alreadyPresentVar = Get-AzureRmAutomationVariable -ResourceGroupName $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'AKVNAme' -ErrorAction Stop\r\n Set-AzureRmAutomationVariable -ResourceGroupName  $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'AKVNAme' -Value $(KeyVaultName) -Encrypted $false\r\n\r\n}\r\ncatch{\r\nNew-AzureRmAutomationVariable -ResourceGroupName  $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'AKVNAme' -Value $(KeyVaultName) -Encrypted $false\r\n}\r\n\r\ntry{\r\n $alreadyPresentVar = Get-AzureRmAutomationVariable -ResourceGroupName $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'ServiceBusAccessPolicyKey' -ErrorAction Stop\r\n Set-AzureRmAutomationVariable -ResourceGroupName  $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'ServiceBusAccessPolicyKey' -Value $serviceBusNamespaceKey.PrimaryKey -Encrypted $true\r\n\r\n}\r\ncatch{\r\nNew-AzureRmAutomationVariable -ResourceGroupName  $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Name 'ServiceBusAccessPolicyKey' -Value $serviceBusNamespaceKey.PrimaryKey -Encrypted $true\r\n} \r\n<\/pre>\n<\/li>\n<li>Add a another Azure PowerShell task\n<img decoding=\"async\" width=\"737\" height=\"69\" class=\"wp-image-39936\" style=\"font-size: 1rem;\" src=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image-1.png\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image-1.png 737w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image-1-300x28.png 300w\" sizes=\"(max-width: 737px) 100vw, 737px\" \/><\/li>\n<li>Provide the following inline script to execute the runbook post deployment using above step and schedule the same with a renewal interval. Here, a 3 month duration has been considered for next run.\n<pre class=\"prettyprint\">try{\r\nRemove-AzAutomationSchedule -Name 'SASTokenRenewal' -ResourceGroupName $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -Force\r\n}\r\ncatch{\r\nwrite-host 'SASTokenRenewal schedule is not pre existing, will be configured.'\r\n}\r\n$StartTime = Get-Date\r\n$StartTime \r\n$StartTime =$StartTime.AddMinutes(15) \r\n$StartTime \r\nNew-AzAutomationSchedule  -Name 'SASTokenRenewal' -ResourceGroupName $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -StartTime $StartTime  -DayInterval 90 \r\n\r\nRegister-AzAutomationScheduledRunbook -Name 'RenewSASToken' -ResourceGroupName $(AutomationRG) -AutomationAccountName $(AutomationAccountName) -ScheduleName 'SASTokenRenewal'\r\n\r\nStart-AzAutomationRunbook -AutomationAccountName $(AutomationAccountName) -Name \"RenewSASToken\" -ResourceGroupName $(AutomationRG)\r\n<\/pre>\n<\/li>\n<li>Provide the appropriate variables in CD pipelines which will be used within both the scripts.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p><strong>NOTE:<\/strong><\/p>\n<ul>\n<li>The <strong>DeploySASTokenRenewalRunbook<\/strong> will deploy the Runbook with all the environment variables require for executing the Runbook. The <strong>Run book Update Schedule <\/strong>step will trigger the runbook post deployment. It will also schedule the runbook for consecutive executions.<\/li>\n<li>The automation account needs to have the following module preinstalled for successful execution of the runbook.\n<ul>\n<li>AzureRM.Automation<\/li>\n<li>AzureRM.Keyvault\n<img decoding=\"async\" width=\"1130\" height=\"331\" class=\"wp-image-39937\" style=\"font-size: 1rem;\" src=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image-2.png\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image-2.png 1130w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image-2-300x88.png 300w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image-2-1024x300.png 1024w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/10\/word-image-2-768x225.png 768w\" sizes=\"(max-width: 1130px) 100vw, 1130px\" \/><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<ul>\n<li>The automation account should be able to perform read\/write operation in Key Vault. Provide (Get,List,Set,Delete) access to ApplicationId of &#8220;AzureRunAsConnection&#8221; listed in &#8220;Connections&#8221; for the automation account.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This article covers the process of generating a service bus token using PowerShell, using an azure runbook to cover token generation and renewal, and the how process can be automated and managed with a CI\/CD pipeline. <\/p>\n","protected":false},"author":582,"featured_media":39938,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[25],"tags":[2571,157,334],"class_list":["post-39934","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","tag-azure-devops","tag-azure-key-vault","tag-servicebus"],"acf":[],"blog_post_summary":"<p>This article covers the process of generating a service bus token using PowerShell, using an azure runbook to cover token generation and renewal, and the how process can be automated and managed with a CI\/CD pipeline. <\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/39934","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=39934"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/39934\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/39938"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=39934"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=39934"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=39934"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}