Connect-AzAccount with Azure Devops Pipeline? - azure

I am finding difficulties in finding the best and secure way to use connect-azaccount with azure devops pipeline. I have in the pipeline the following this simple powershell script which is used to create azure resources. Just to simplify things I only used the creation of a resource group:
$Location = "Location Name"
$resourceGroupName = "Resource Group Name"
try {
#Creation of Resource Group
$resourceGroup = Get-AzResourceGroup -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue
if($null -eq $resourceGroup)
{
New-AzResourceGroup -Name $resourceGroupName -Location $Location
}
else
{
Write-Host "The ResourceGroup with the name: $resourceGroupName already exists."
}
}
catch
{
Write-Host "Error occurred: $_"
}
The problem here is when the pipeline is being run and it reaches the Powershell task, it gives me an error, Error occurred: Run Connect-AzAccount to login.
My issue here is that I honestly don't know which way is the most secure way to connect without typing any user credentials. It should directly connect and create the resources. Note that I am using Multi-Factor Authentication. In order to achieve that I found several solutions but I need help in choosing the best way. I found several solutions by adding a powershell task in the Yaml file. Here is the Yaml showing the powershell task to run the script:
- task: PowerShell#2
inputs:
filePath: '$(Pipeline.Workspace)/Deploy/functionapp.ps1'
Option 1:
Connect-AzAccount -Tenant 'xxxx-xxxx-xxxx-xxxx' -SubscriptionId 'yyyy-yyyy-yyyy-yyyy'
Now the problem here is that the Tenant ID and Subscription are going to be visible in the code and that is a very bad practice
Option 2 is to use the following script:
$User = "xxx#xxxx.onmicrosoft.com"
$PWord = ConvertTo-SecureString -String "<Password>" -AsPlainText -Force
$tenant = "<tenant id>"
$subscription = "<subscription id>"
$Credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $User,$PWord
Connect-AzAccount -Credential $Credential -Tenant $tenant -Subscription $subscription
This is very similar to the first, but if I am not mistaken it is limited to a specific user.
Option 3 is to use a service principal:
$azureAplicationId ="Azure AD Application Id"
$azureTenantId= "Your Tenant Id"
$azurePassword = ConvertTo-SecureString "strong password" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
Connect-AzAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal
I don't know if creating a service principal will incur any costs and what steps should I do to make it work.
I am honestly new to all this, can someone please provide me what are the exact steps to achieve this. Thank you for your answers :)

The most secure way is to create an Azure Resource Manager service connection and use it in your pipeline. You can create it using automated way, or manually using previously created service principal.

Related

Azure Automation Variables

I am trying to make a code using PowerShell so that secrets are not hardcoded on my runbook so that it will not be exposed in the script. I created encrypted variables in my automation account. These variables are AppID, AppSecret and TenantID.
This is the part of the script to login automatically to Azure. I didn't use managed identity for some compatibility reasons with the script.
My script is running fine when secrets and IDs are hardcoded but when I created variables it is not working. Error message is "Run Connect-AzAccount". Below is my code. Need help on how to correct this. Thank you in advance.
$AzVariableApplicationID = 'AppID'
$AzVariableAppSecret = 'AppSecret'
$AzVariableTenantID = 'TenantID'
$AppID = Get-AzAutomationVariable -Name $AzVariableApplicationID
$AppSecret = Get-AzAutomationVariable -Name $AzVariableAppSecret
$TenantID = Get-AzAutomationVariable -Name $AzVariableTenantID
$SecureSecret = $AppSecret | ConvertTo-SecureString -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential `
-ArgumentList $AppID, $SecureSecret
Connect-AzAccount -ServicePrincipal -Credential $Credential -Tenant $TenantID
As described in PsCustom Object - Hitchikers GUID(e) to Automation
, It is not possible to retrieve values for encrypted variables as they’re available within the runbook at runtime via the Get-AutomationVariable cmdlet
I found an alternative approach to "Connect Azure" by using "Certificate-based authentication" inside PowerShell runbook without hardcoding the values:
Created a new Service principal and provided the "Owner" role access to avoid any restrictions.
To authenticate via service principal, I create a new self-signed certificate with the command:
$cert=New-SelfSignedCertificate -Subject "CN=xxxxxCert" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature
Upload a certificate under Certifications & Secrets:
Click windows + R to open the run box and give certmgr.msc as shown here.
Export a certificate without private key.
Upload a certificate in the below path:
AzureAD -> App registrations -> Serviceprincipal
Now, I have exported the same certificate with key and uploaded inside my automation account to authenticate Service principal connection:
Added an "Azure Service Principal" connection inside automation accounts by providing "ApplicationID, TenantID, Certificate Thumbprint" of my Service principal as shown:
Inside PowerShell runbook, I ran the below script that works for me:
$connectionName = "serviceprincipalname"
try
{
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRMAccount
-ServicePrincipal `
-TenantID $servicePrincipalConnection.TenantID `
-ApplicationID $servicePrincipalConnection.applicationID `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found. "
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
Logged in to Azure:
Register an App in App registrations and create a service principal in AzureAD

Azure PowerShell-Runbook

Working on this as below - Using a power-shell script inside the Automation Account for run-book. The power-shell script will help in adding a rule inside the resource of the function-app of the networking rule. But somehow the following happens -
Not able to login the azure account
And it says Subscription ID doesn't exists. (Login is done via Service principle)
Code for reference
$azureAplicationId="XXXX"
$azureTenantId="XXXXX"
$azurePassword=ConvertToSecureString "XXXXXX" -AsPlainText -Force
$psCred=New-Object System.Management.Automation.PSCredential($azureAplicationId ,$azurePassword)
Login-AzureRmAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal
Select-AzureSubscription -SubscriptionId "XXXXXX"
Add-AzWebAppAccessRestrictionRule -ResourceGroupName "XXXXX" -WebAppName "XXXXX" -Name "iprule" -Priority 100 -Action Allow -IpAddress x.x.x.x/x –

Attempting to remove sql db in azure gives error "No default subscription has been designated"

I am currently trying to write a powershell script which logs into azure and then deletes an SQL database.
When it gets to the database deletion it gives an error:
Remove-AzureSqlDatabase : No default subscription has been designated. Use Select-AzureSubscription -Default <subscriptionName> to set the default
subscription.
When i try to add a default subscription with Select-AzureSubscription -Default -SubscriptionName Pay-As-You-Go i get an error aswell:
Select-AzureSubscription : The subscription name Pay-As-You-Go doesn't exist.
I'm confused as to what the problem is and have tried connecting to the account via connect-AzAccount aswell.
The full script is:
$passwd = ConvertTo-SecureString password -AsPlainText -Force
$pscredential = New-Object System.Management.Automation.PSCredential('accountname', $passwd)
Connect-AzureRmAccount -Credential $pscredential -Tenant "tenant string"
# Set-AzContext -SubscriptionId "subscription id"
Select-AzureSubscription -Default -SubscriptionName Pay-As-You-Go
# Get-AzureSubscription -SubscriptionName “Pay-As-You-Go” | Select-AzureSubscription -Default
Remove-AzureSqlDatabase -ServerName migrate -DatabaseName "AWS-Copy"
You could not mix the three powershell module Azure, Az, AzureRm together, and if you have installed the Az module, I recommend you to uninstall the AzureRm module, it was deprecated and will never be updated.
To remove sql db with Az module, your script should be like below. Make sure your account has an RBAC role(e.g. Owner, Contributor) of your subscription/SQL Server.
$passwd = ConvertTo-SecureString password -AsPlainText -Force
$pscredential = New-Object System.Management.Automation.PSCredential('accountname', $passwd)
Connect-AzAccount -Credential $pscredential -Tenant "<tenant-id>"
Set-AzContext -Subscription "<subscription-id>"
Remove-AzSqlDatabase -ResourceGroupName "<ResourceGroupName>" -ServerName "<ServerName>" -DatabaseName "<DatabaseName>"

Connect-AzAccount - how to avoid azure device authentication?

I have installed the PowerShell 6.1.3 version and
I want to get a connection to the Azure account using the following Azure PowerShell command:
Connect-AzAccount -Tenant <tenantId> -Subscription <subId>
After entering this command I get the warning with the url and some code.
Then I have to go to the URL and enter the code there. After that, I get a connection to the Azure account.
Are there any ways to avoid this confirmation?
I've also tried to do it using the following command:
az login -u <username> -p <password>
This command only returns some account information(subscriptionId, tenantId etc) but it doesn't install a connection to this account.
1.To login with the user account, try the command as below, make sure your account doesn't enable the MFA(Multi-Factor Authentication).
$User = "xxx#xxxx.onmicrosoft.com"
$PWord = ConvertTo-SecureString -String "<Password>" -AsPlainText -Force
$tenant = "<tenant id>"
$subscription = "<subscription id>"
$Credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $User,$PWord
Connect-AzAccount -Credential $Credential -Tenant $tenant -Subscription $subscription
2.You can also use a service principal to login, use the command as below.
$azureAplicationId ="Azure AD Application Id"
$azureTenantId= "Your Tenant Id"
$azurePassword = ConvertTo-SecureString "strong password" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
Connect-AzAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal
See a similar issue I answered here, it use the old AzureRM module, for Az, just change the last line.
If you are not familiar with service principal, Also see : How to: Use the portal to create an Azure AD application and service principal that can access resources, the application id and authentication key are the Azure AD Application Id and strong password you need.
You have 2 options.
Sign in with credentials (Requires Az.Accounts v 1.2.0 or higher)
You can also sign in with a PSCredential object authorized to connect to Azure. The easiest way to get a credential object is with the Get-Credential cmdlet. When run, this cmdlet will prompt you for a username/password credential pair.
$creds = Get-Credential
Connect-AzAccount -Credential $creds
Sign in with a service principal
Service principals are non-interactive Azure accounts. Like other user accounts, their permissions are managed with Azure Active Directory. By granting a service principal only the permissions it needs, your automation scripts stay secure.
To learn how to create a service principal for use with Azure PowerShell, see Create an Azure service principal with Azure PowerShell.
Source: https://learn.microsoft.com/en-us/powershell/azure/authenticate-azureps?view=azps-1.3.0
If Multi Factor Enabled then also below logic should work
$clientId = "***********************"
$clientSecret = "********************"
$tenantId = "***********************"
$tempPassword = ConvertTo-SecureString "$clientSecret" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($clientId ,
$tempPassword)
Connect-AzAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal

login to azure account without popup using powershell

I'm trying to create Azure VM using powershell.I have also the script to create it.
First I need to login into Azure account :
Login-AzureRMAccount
This gives a pop-up to enter the credentials.
Second I need to run the below script:
$UserName = "username"
$Password = ConvertTo-SecureString "password" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($UserName, $Password)
New-AzureRmVm `
-ResourceGroupName "RG1" `
-Name "VM1" `
-ImageName "Image1" `
-Location "West US" `
-Credential $psCred
This is creating the VM successfully.
But now , I need to make these scripts run automatically, when ever there is requirement. The problem I'm facing is, the login step gives a popup to enter the credentials which I do not want. So I have tried something like this, but didn't work.
$username = "loginname#organization.com"
$SecurePassword = ConvertTo-SecureString "password" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($username, $SecurePassword)
Login-AzureRmAccount -Credential $cred
The error message it is giving is :
Login-AzureRmAccount : accessing_ws_metadata_exchange_failed: Accessing WS metadata exchange failed: The underlying connection was closed: An unexpected error occurred on a send.
At line:4 char:1
+ Login-AzureRmAccount -Credential $cred
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Connect-AzureRmAccount], AadAuthenticationFailedException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand
Can anyone tell me what this means and how to rectify this? Thanks!
If you are planning to automate any services into Azure using PowerShell, then I'd recommend connecting azure using Service Principal rather than your own credentials, it will be a secure way to connect.
What is Service principal?
An Azure service principal is a security identity used by user-created
apps, services, and automation tools to access specific Azure
resources. Think of it as a 'user identity' (username and password or
certificate) with a specific role, and tightly controlled permissions.
It only needs to be able to do specific things, unlike a general user
identity. It improves security if you only grant it the minimum
permissions level needed to perform its management tasks.
Follow this tutorial to create a service principal
I also have published a sample PowerShell workflow into Microsoft gallery for creating Service Principal you can also follow that.
Once you created your service principal, you can use the below PowerShell commands to login into azure without any popup's
$applicationId = "<service prinicple application id>";
$securePassword = "<service prinicple password>" | ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $applicationId, $securePassword
Connect-AzureRmAccount -ServicePrincipal -Credential $credential -TenantId "<your tenantid>"
Update1:
For some reason/bug the above will get fails. Refer this github issue
To solve this
Add the two lines before the script
Import-Module -Name AzureRM.Profile
Remove-AzureRmAccount
Update 2:
AzureRM will no longer receive new cmdlets or features. However, the AzureRM module is still officially maintained and will get bug fixes through December 2020.
You have to use the new Azure PowerShell Az module
Basically you can achieve this for all of your PowerShell sessions by adding the Logging in part as part of the $PSProfile. I use this trick to skip the login popup, so whenever i open powershell my account is automatically logged in.
Open Windows PowerShell as an administrator
Type Notepad $profile
A notepad file will be opened and here you can paste the below code to
log in automatically whenever it is opened.
$username = “”
$password = “”
$securepasswd = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ($username, $ securepasswd)
Connect-AzureRmAccount -Credential $cred

Resources