Skip to content

Commit 2330247

Browse files
authored
Merge pull request Azure#3076 from Azure/autoTest
Run PS Smoke tests with service principal
2 parents be57487 + 9422d7e commit 2330247

File tree

7 files changed

+572
-56
lines changed

7 files changed

+572
-56
lines changed

documentation/RunSmokeTests.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Running Tests with Auto Login #
2+
3+
This script will allow to login as long as you have required certificate installed on your machine
4+
5+
## WorkFlow #1 ##
6+
7+
1. Will Check if the certificate is installed
8+
2. If not will ask you to login (one time) to access KeyVault
9+
3. Download Certificate, install certificate on the machine (will prompt to set certificate password)
10+
4. Login using the recently installed certificate
11+
5. Set the context for Test Subscription
12+
6. Download PublishSettings file from keyVault to enable log into ASM
13+
7. Run Tests
14+
8. Clean up - Delete any locally downloaded certificates or publishsettings file
15+
16+
## WorkFlow #2 ##
17+
18+
1. Check if certificate is installed
19+
2. If Yes, log in using certificate
20+
3. Download publishsettings file from KeyVault
21+
4. Log into ASM using publish settings file
22+
5. Run Tests
23+
6. Clean up
24+
25+
26+
The script that kick starts running test is RunInstallationTests.ps1
27+
This script takes two parameters
28+
29+
1. uninstallLocalCert
30+
1. $true: will uninstalled existing certificate
31+
2. $false: will not uninstall existing certificate
32+
33+
1. runOnCIMachine
34+
1. $true:
35+
1. this mode will allow to fail fast, especially if it detects local certificate is not installed and needs manual login, it will fail
36+
2. this will also set the DebugPreference = "Continue", this allows you to get more verbose output of the various cmdlets that are executed as part of the test
37+
2. $false: will check if the local certificate is installed, if not manually will prompt user to log in and install the certificate from KeyVault
38+
39+
40+

tools/InstallationTests/Assert.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# ----------------------------------------------------------------------------------
1+
# ----------------------------------------------------------------------------------
22
#
33
# Copyright Microsoft Corporation
44
# Licensed under the Apache License, Version 2.0 (the "License");
Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
<#
2+
# ----------------------------------------------------------------------------------
3+
#
4+
# Copyright Microsoft Corporation
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# ----------------------------------------------------------------------------------
15+
16+
This script will allow to login as long as you have required certificate installed on your machine
17+
18+
WorkFlow# 1
19+
===========
20+
1) Will Check if the certificate is installed
21+
2) If not will ask you to login (one time) to access KeyVault
22+
3) Download Certificate, install certificate on the machine (will prompt to set certificate password)
23+
4) Login using the recently installed certificate
24+
5) Set the context for Test Subscription
25+
6) Download PublishSettings file from keyVault to enable log into ASM
26+
8) Run Tests
27+
9) Clean up - Delete any locally downloaded certificates or publishsettings file
28+
29+
WorkFlow# 2
30+
============
31+
1) Check if certificate is installed
32+
2) If Yes, log in using certificate
33+
3) Download publishsettings file from KeyVault
34+
4) Log into ASM using publish settings file
35+
5) Run Tests
36+
6) Clean up
37+
38+
TODO:
39+
1) Currently ServicePrincipal ClientId is hard-Coded in script
40+
Will need to push that in KeyVault and use it to get the ClientId every single time you need to login using service principal
41+
Will also need a way to replace existing ClientId ID, if Service principal is recreated.
42+
<#--------Current certificate expires 10/7/2017 --------->
43+
2) Will need a way check if local certificate is near expiry, if yes create a new one in keyVault and delete existing one.
44+
3) When replacing Certificate, you will also need to set new role Assignment using the new certificate.
45+
46+
Issues:
47+
1) During the very first log in using certificate, an error pops up "Login-AzureRmAccount : No certificate was found in the certificate store with thumbprint System.Object[]"
48+
This is a transient error, but eventually the login is successful as it finds the certificate in Currentuser store
49+
So after the first try, this error no longer shows up.
50+
Will open an issue to investigate where we try both the cert store simultenously rather we should try Currentuser and if not found then try LocalMachine.
51+
#>
52+
53+
$global:gPsAutoTestADAppId = 'b8a1058e-25e8-4b08-b40b-d8d871dda591'
54+
$global:gPsAutoTestSubscriptionName = 'Node CLI Test'
55+
$global:gPsAutoTestSubscriptionId = '2c224e7e-3ef5-431d-a57b-e71f4662e3a6'
56+
57+
$global:gTenantId = '72f988bf-86f1-41af-91ab-2d7cd011db47'
58+
$global:gLocalCertSubjectName = 'CN=PsAutoTestCert, OU=MicrosoftAzurePsTeam'
59+
$global:gPfxLocalFileName = "PsAutoTestCert.pfx"
60+
$global:gpubSettingLocalFileName = "NodeCLITest.publishsettings"
61+
62+
$global:gVaultName = 'KV-PsSdkAuto'
63+
$global:gPsAutoResGrpName = 'AzurePsSdkAuto'
64+
65+
$global:gLocalCertStore = 'Cert:\CurrentUser\My'
66+
$global:gCertPwd = ''
67+
$global:gLoggedInCtx = $null
68+
$global:localPfxDirPath = [Environment]::GetEnvironmentVariable("TEMP")
69+
70+
#KV KeyVaules
71+
$global:kvSecKey_PsAutoTestCertNameKey = 'PsAutoTestCertName'
72+
$global:gPsAutoTestADAppUsingSPNKey = 'PsAutoTestADAppUsingSPN'
73+
$global:gkvSecKey_PubSettingFileNameKey = 'NodeCliTestPubSetFile'
74+
$global:gKVKey_ADAppIdKey = "PsAutoTestAppUsingCertAppId"
75+
76+
77+
Function Check-LoggedInContext()
78+
{
79+
if($gLoggedInCtx -eq $null)
80+
{
81+
Write-Error "'$global:gPsAutoTestSubscriptionName' subcription does not exist in the list of available subscriptions. Make sure to have it to run the tests"
82+
Exit
83+
}
84+
}
85+
86+
Function Get-AutomationTestCertificate()
87+
{
88+
[OutputType([System.Security.Cryptography.X509Certificates.X509Certificate])]
89+
Param ($cert)
90+
91+
if($gLoggedInCtx -ne $null)
92+
{
93+
#Download Certificate from KeyVault
94+
$downloadedCertPath = Download-TestCertificateFromKeyVault
95+
96+
#Install Certificate locally
97+
Install-TestCertificateOnMachine $downloadedCertPath
98+
99+
#Verify it was installed locally
100+
$cert = Get-LocalCertificate
101+
if($cert -eq $null)
102+
{
103+
throw [System.ApplicationException] "Unable to retrieve Automation Test Certificate '$gLocalCertSubjectName'"
104+
}
105+
}
106+
return $cert
107+
}
108+
109+
Function Get-LocalCertificate()
110+
{
111+
#TODO: Handle case whgere we get multiple test certificates with exactly the same subject
112+
$cert = Get-ChildItem $gLocalCertStore | Where-Object {$_.Subject -eq $Global:gLocalCertSubjectName}
113+
if($cert -eq $null)
114+
{
115+
Log-Info "Trying to find certificate in LocalMachine"
116+
$cert = Get-ChildItem 'Cert:\LocalMachine\My' | Where-Object {$_.Subject -eq $Global:gLocalCertSubjectName}
117+
}
118+
119+
return $cert
120+
}
121+
122+
Function Download-PublishSettingsFileFromKv([string] $localFilePathToDownload)
123+
{
124+
$dirPath = [System.IO.Path]::GetDirectoryName($localFilePathToDownload)
125+
$pubFileSecContents = Get-AzureKeyVaultSecret -VaultName $global:gVaultName -Name $global:gkvSecKey_PubSettingFileNameKey
126+
Log-Info "Ready to download Publishsettings file to '$localFilePathToDownload' from Azure KeyVault"
127+
128+
if([System.IO.Directory]::Exists($dirPath) -eq $true)
129+
{
130+
[System.IO.File]::WriteAllText($localFilePathToDownload, $pubFileSecContents.SecretValueText)
131+
}
132+
else
133+
{
134+
throw [System.IO.DirectoryNotFoundException] "$dirPath does not exists"
135+
}
136+
137+
Log-Info "Successfully downloaded Publishsettings file to '$localFilePathToDownload'"
138+
}
139+
140+
Function Install-TestCertificateOnMachine([string] $localCertPath)
141+
{
142+
#$certContentType = "application/x-pkcs12"
143+
if([System.IO.File]::Exists($localCertPath) -ne $true)
144+
{
145+
$localCertPath = Download-TestCertificateFromKeyVault
146+
}
147+
148+
$pwd = Get-LocalCertificatePassword
149+
$secCertPwd = ConvertTo-SecureString -String $pwd -AsPlainText -Force
150+
151+
Log-Info "Ready to install certificate to '$global:gLocalCertStore'"
152+
Import-PfxCertificate -FilePath $localCertPath -CertStoreLocation $gLocalCertStore -Password $secCertPwd
153+
154+
$installedCert = Get-LocalCertificate
155+
if($installedCert -eq $null)
156+
{
157+
throw [System.ApplicationException] "Unable to retrieve installed certificate for running automation test"
158+
}
159+
else
160+
{
161+
Log-Info "Successfully installed certificate to '$global:gLocalCertStore'"
162+
}
163+
}
164+
165+
Function Download-TestCertificateFromKeyVault()
166+
{
167+
168+
Check-LoggedInContext
169+
$kvCertSecret = Get-AzureKeyVaultSecret -VaultName $global:gVaultName -Name $global:kvSecKey_PsAutoTestCertNameKey
170+
171+
#ToDo: Handle the case where access denied to keyVault will result in an attempt to create a new certificate (which will fail again, but needs to be handled)
172+
#if($kvCertSecret -eq $null)
173+
#{
174+
# Log-Info "Unable to get certificate from Azure KeyVault"
175+
# $kvCertSecret = Create-TestAutoCertificateInKv $gVaultName $kvSecKey_PsAutoTestCertNameKey
176+
#}
177+
178+
#Once we create certificate and get it, we store it locally
179+
if($kvCertSecret -ne $null)
180+
{
181+
$kvSecretBytes = [System.Convert]::FromBase64String($kvCertSecret.SecretValueText)
182+
$certCollection2 = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
183+
$certCollection2.Import($kvSecretBytes, $null, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
184+
185+
#Save Pfx locally
186+
$pwd = Get-LocalCertificatePassword
187+
$certPwdProtectedInBytes = $certCollection2.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, $pwd)
188+
$pfxLocalFilePath = [System.IO.Path]::Combine($global:localPfxDirPath, $global:gPfxLocalFileName)
189+
[System.IO.File]::WriteAllBytes($pfxLocalFilePath, $certPwdProtectedInBytes)
190+
191+
#We are not going the .cer route for now, rather use publishSettings file
192+
#Save .cer file location to be uploaded to the management portal
193+
#$kvAutoTestCert = Get-AzureKeyVaultCertificate -VaultName $vaultName -Name $certName
194+
#$cerLocalFilePath = [Environment]::GetFolderPath("Desktop") + "\PsAutoTestCert.cer"
195+
#$certBytes = $kvAutoTestCert.Certificate.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
196+
#[System.IO.File]::WriteAllBytes($cerLocalFilePath, $certBytes)
197+
198+
Log-Info "Successfully downloaded certificate at '$pfxLocalFilePath'"
199+
}
200+
201+
return $pfxLocalFilePath
202+
}
203+
204+
Function Get-LocalCertificatePassword()
205+
{
206+
if([string]::IsNullOrEmpty($global:gCertPwd) -eq $true)
207+
{
208+
$global:gCertPwd = Read-Host "Please enter certificate password that is ready to be installed on your machine"
209+
}
210+
211+
return $global:gCertPwd
212+
}
213+
214+
Function Login-AzureRMWithCertificate([bool]$runOnCIMachine=$false)
215+
{
216+
$appId = $global:gPsAutoTestADAppId
217+
218+
$localCert = Get-LocalCertificate
219+
if($localCert -eq $null)
220+
{
221+
If($runOnCIMachine -eq $false)
222+
{
223+
$global:ErrorActionPreference = "SilentlyContinue" #the very first time you install cert, you get an error when you login
224+
#we could not find certificate installed locally, get it from KeyVault
225+
Login-InteractivelyAndSelectTestSubscription
226+
$localCert = Get-AutomationTestCertificate
227+
#TODO: Handle the case where local certificate is available, but for some reason Service Principal is not available
228+
}
229+
else
230+
{
231+
throw [System.ApplicationException] "Local Certificate missing on machine and 'runOnCIMachine' is passed as $runOnCIMachine"
232+
}
233+
}
234+
235+
$thumbprint = $localCert.Thumbprint
236+
#Seen cases where for some odd reason, $thumb is being evaluated as object rather than a string, but this does not happen consistently
237+
$thumbStr = [System.Convert]::ToString($thumbprint.ToString())
238+
239+
#Update the LoggedInCtx
240+
$gLoggedInCtx = Login-AzureRmAccount -ServicePrincipal -CertificateThumbprint $thumbStr -ApplicationId $appId -TenantId $global:gTenantId
241+
$global:ErrorActionPreference = "Stop" #setting it back to default option that were set in Test-Setup
242+
}
243+
244+
Function Login-AzureWithCertificate()
245+
{
246+
$fullPath = [System.IO.Path]::Combine($PSScriptRoot, $global:gpubSettingLocalFileName)
247+
248+
if([System.IO.File]::Exists($fullPath) -ne $true)
249+
{
250+
Download-PublishSettingsFileFromKv $fullPath
251+
}
252+
253+
Import-AzurePublishSettingsFile -PublishSettingsFile $fullPath
254+
}
255+
256+
Function Login-InteractivelyAndSelectTestSubscription()
257+
{
258+
Log-Info "Login interactively....."
259+
$global:gLoggedInCtx = Login-AzureRmAccount
260+
261+
Check-LoggedInContext
262+
Log-Info "Selecting '$global:gPsAutoTestSubscriptionId' subscription"
263+
$global:gLoggedInCtx = Select-AzureRmSubscription -SubscriptionId $global:gPsAutoTestSubscriptionId
264+
265+
return $global:gLoggedInCtx
266+
}
267+
268+
Function Login-Azure([bool]$deleteLocalCertificate=$false, [bool]$runOnCIMachine=$false)
269+
{
270+
try
271+
{
272+
Remove-AllSubscriptions
273+
274+
if($deleteLocalCertificate -eq $true)
275+
{
276+
Delete-LocalCertificate
277+
}
278+
279+
Login-AzureRMWithCertificate $runOnCIMachine
280+
Select-AzureRmSubscription -SubscriptionId $global:gPsAutoTestSubscriptionId -TenantId $global:gTenantId
281+
282+
Login-AzureWithCertificate
283+
Select-AzureSubscription -SubscriptionId $global:gPsAutoTestSubscriptionId -Current
284+
}
285+
finally
286+
{
287+
Delete-DownloadedCertAndPubSetting
288+
}
289+
}
290+
291+
Function Log-Info([string] $info)
292+
{
293+
$info = [string]::Format("[INFO]: {0}", $info)
294+
Write-Host $info -ForegroundColor Yellow
295+
}
296+
297+
Function Log-Error([string] $errorInfo)
298+
{
299+
$errorInfo = [string]::Format("[INFO]: {0}", $errorInfo)
300+
Write-Error -Message $errorInfo
301+
}
302+
303+
Function Delete-LocalCertificate()
304+
{
305+
$cert = Get-LocalCertificate
306+
if($cert -ne $null)
307+
{
308+
$certPath = $cert.PSPath
309+
Log-Info "Deleting local certificate $certPath"
310+
Remove-Item $cert.PSPath
311+
}
312+
}
313+
314+
Function Delete-DownloadedCertAndPubSetting
315+
{
316+
$pfxFilePath = [System.IO.Path]::Combine($global:localPfxDirPath,$global:gPfxLocalFileName)
317+
if([System.IO.File]::Exists($pfxFilePath) -eq $true)
318+
{
319+
#Log-Info "Deleting '$pfxFilePath'"
320+
Remove-Item $pfxFilePath
321+
}
322+
323+
$pubSettingFile = [System.IO.Path]::Combine($PSScriptRoot,$global:gpubSettingLocalFileName)
324+
if([System.IO.File]::Exists($pubSettingFile) -eq $true)
325+
{
326+
#Log-Info "Deleting '$pubSettingFile'"
327+
Remove-Item $pubSettingFile
328+
}
329+
}

0 commit comments

Comments
 (0)