Some time ago a friend asked me the easiest way to get code from a specific folder and a specific version in TFVC. The goal is avoiding using Get Specific Version because he do not want to overwrite the Workspace folder he is using, he want also to avoid creating another workspace only to do a one-shot get of a folder.

It turns out that the easiest way to accomplish this task is from Web Interface, because it has the capability of browsing and downloading code as zip. You can simply navigate to the CODE hub in web interface, choose the folder you want to download and use the context menu of desired folder to download everything as a single zip file.

image

Figure 1: Browse and download code from the Web Interface.

But wait, this will download the latest version of the code, not a specific version. The cool part of the web interface is that if you just append #version=xxx where xxx is the changeset-id you want to download, you can browse the code of that specific changeset, and you can also download as Zip that specific version. If you just look at the url, you can easily spot out that downloading the code as zip is just a matter of calling the right url

https://gianmariaricci.visualstudio.com/DefaultCollection/Experiments/_api/_versioncontrol/itemContentZipped?repositoryId=&path=%24%2FExperiments%2Ftrunk&version=96&__v=5

You can simply change the version parameter and you are able to download every version of your code as zip with a simple call and without resorting to API or external tool. Just copy and paste url inside your browser and you are done. If you have not previously authenticated with your TFS or VSO you will be prompted for credentials, then the file is downloaded.

I’ve showed you examples with Visual Studio Online, but you can use the very same technique against your on-premise TFS.

Gian Maria.

Tags:

No comments

It could happens when you clone a Git Repository with submodules, issuing a git submodule update command, you are prompted with this error error.

Cloning into ‘src/xxxx’…
Warning: Permanently added the RSA host key for IP address xxx.xxx.xxx.xxx to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

If you search in the internet for the cause of errors, you can find some people suggesting that the url specified in .gitmodules file is wrong and should be changed, here is my .gitmodule

[submodule "src/CQRS"]
     path = src/CQRS
     url = git@github.com:xxxxxx/cqrs.git
     branch = master
    

You could change the url configuration to https url and everything works, but this is not the perfect solution, because the address git@github.com is perfectly valid, but probably there is some problem with your RSA keys stored in Github (or you never configured RSA Keys for your account). In my situation, my RSA Keys had some problem and I needed to recreate another one. If you do not know what a RSA key is and how to create a RSA Key to connect to github I strongly suggest you reading the guide: Generating SSH Keys.

Once you configure a valid certificate in github your submodule should word without problem.

Gian Maria.

Tags: ,

No comments

Using DPAPI to encrypt password in builds suffers from a serious drawback, the password can be decrypted only by code that runs on the very same computer used to encrypt the password. You can overcome this limitation using roaming profiles, but it is not a option in many scenario. Another technique to enable multiple build servers to decrypt a password is using certificates. In PowerShell is really easy to use a certificate to encrypt/decrypt string and this article will show you how to secure a password in TFS Build definition using Certificates.

First step is generating a valid certificate, this is easy thanks to MakeCert utility, just open a Developer Command Prompt and type

MakeCert.exe -r -pe -n “CN=www.cyberpunk.local” -sky exchange -ss my -len 2048 -e 01/01/2020

This command creates a certificate in your certificate store. To view it you should type certmgr to open the Certificates Manager Console. Your newly created certificate should now appear in the list of certificates.

image

Figure 1: Your newly created certificate appears in certificate store.

Double Clicking the certificate opens detail windows where you can find the value of Thumbprint property (Figure 2). This property is useful because it uniquely identifies this certificate in certificate store, and it should be used to load correct certificate in PowerShell script.

image

Figure 2: Grab the Thumbprint of the certificate in detail pane.

You should grab the thumbprint from the certificate details, it should be a string like: f02e4c0e13e26d25065cc0db1d03450acaef90d6. Just copy from the details pane, remove all the spaces and you are ready to use this certificate to Encrypt and Decrpyt a string. Here is the PowerShell script that uses this certificate to Encrypt and then Decrypt a string.

$cert = Get-Item -Path Cert:\CurrentUser\My\f02e4c0e13e26d25065cc0db1d03450acaef90d6 -ErrorAction Stop
                                            
$decrypted = ""
$bytesDecrypted = ""
$bytesToDecrypt = ""
$pwd = 'mySecurePwd'
$enc = [system.Text.Encoding]::UTF8
$pwdBytes = $enc.GetBytes($pwd) 

$encryptedPwdBytes = $cert.PublicKey.Key.Encrypt($pwdBytes, $true)
$EncryptedPwd = [System.Convert]::ToBase64String($encryptedPwdBytes)

Write-Output "`r`nEncrypted Password IS:"
Write-Output $EncryptedPwd

#Now decrypt.
$bytesToDecrypt = [System.Convert]::FromBase64String($EncryptedPwd)
$bytesDecrypted = $cert.PrivateKey.Decrypt($bytesToDecrypt, $true)

$decrypted = $enc.GetString($bytesDecrypted)

Write-Output "`r`nDecryptedPassword is: $decrypted"

As you can see using the certificate is straightforward, you just grab a reference to certificate with the Get-Item using the thumbprint and then it is just a matter of calling Encrypt method of the public key object stored inside the certificate and convert to Base64 to be conveniently represented as a string. To decrypt you can call Decrypt method of the Private Key object.

If you does not know how a RSA key pair works, here is the basic concept. The certificate contains two keys, one is the Public Key, and the other is the Private Key. You use the public key to encrypt a string and the resulting encrypted string can be decrypted only by the Private Key. Public key used to encrypt the string cannot be used to decrypt it. This is the reason why RSA is called an Asymmetric Algorithm.

Now return to the Certificate manager, and press “Export” button to export the certificate, choose to export only the public key, choose DER format and export the certificate to a folder of your computer. Then press “Export” again but now choose to export the private key, choose the PKCS format and then use a password to protect the exported file. A password is required because the private key is the information that you need to keep secure from the eyes of the public. Now you should have two exported files, one with .cer extension that contains only the public key, the other with .pfx extension containing also the private key.

image

Figure 3: Exported certificates in my filesystem.

Now remove the certificate from Certificate Manager, and try to run again the script to encrypt and decrypt the string, you should now receive an error from Get-Item, telling you that the required path does not exists. This confirms that the certificate was removed from your certificate store. Now press the “import” button on Certificate Manager and import the previously exported public key, the file public.cer in my example and run the script again to verify that you are able to encrypt a string but you cannot decrypt, because you have only the public key.

image

Figure 4: Now that you have only the public key, you are able only to encrypt and you could not decrypt anymore the string.

To verify that you can decrypt password using Private Key, press Import button again on the Certificate Store and import the Private.pfx certificate. You will be prompted to enter the password you use during the export, and if you look at the options you can verify that there is an important option called “mark this key as exportable”, that is turned off by default.

image

Figure 5: Importing a certificate with Private key in certificate store

This option is really important, because this prevents users to further export the private key to another computer. Once you imported the Private certificate, you can verify that pressing the Export button does not permit you to choose the option to export the Private Key. Once the certificate with private key is imported you are now able to decrypt the password.

Thanks to asymmetric key you can simply store the certificate with the public key in any network share, everyone can access the certificate, install it and securely encrypt a password because only people with the private key can decrypt it. Now you should login in every Build Machine with credential of TfsBuild, and import the certificate with the Private key to personal certificate store, do not mark the key as exportable. Now you can use Certificates instead of DPAPI to encrypt and decrypt password during the build. This script will work in every build server where you have installed the certificate for the user TfsBuidl. Here is the script.

Param
(
[string] $url = "http://webtest1.cyberpunk.local:10000/MyService/Index",
[string] $username = "",
[string] $password = ""
)

Write-Host $password
$cert = Get-Item -Path Cert:\CurrentUser\My\f02e4c0e13e26d25065cc0db1d03450acaef90d6 -ErrorAction Stop
Write-Host $cert.PrivateKey.KeySize
$bytesToDecrypt = [System.Convert]::FromBase64String($password)

$bytesDecrypted = $cert.PrivateKey.Decrypt($bytesToDecrypt, $true)
$enc = [system.Text.Encoding]::UTF8
$plainText = $enc.GetString($bytesDecrypted)

Write-Host "Invoking-Service"

$retValue = Invoke-RestMethod $url"?username=$username&password=$plainText"  

Write-Host "ReturnValueIs: "$retValue.Message

This script simply decrypt the password and call a simple REST service just to verify that the password was decrypted with success. Here is the output of the build.

image

I want to remember again that this technique does not secure the password for people that can schedule a new build in TFS. Any person that can schedule a new build can create a PowerShell script that decrypt a password and print it in build output, grab an encrypted password from another build definition and let this script decrypt it.

This is the same technique I used with the above script where I dump the password in clear format in Build output, just to verify that decryption is ok. Any other user with permission to schedule a build could have scheduled a build running a similar script to decrypt password store by other people.

Gian Maria.

Related Articles

Tags:

1 Comment

I’ve installed some weeks ago a new server, and at the time of installation I did the really bad error of not fully checking BIOS settings. This week I moved a couple of SSD to that server, because it will be used for virtualization, and I did noticed that my Vertex 4 is performing really slower respect the original system, so I immediately checked and verified that I forgot to enable AHCI in the BIOS.

SHAME ON ME!!!!!

If you ever had this problem in the past, you knows that if you simply reboot your machine, enable AHCI in the BIOS and reboot again in Windows you will be welcomed with a beautiful Blue Screen telling you that the system is not able to boot.

With windows server 2012 I found that a reboot in Safe Mode is enough. Just reboot the machine, enter in the BIOS, then enable AHCI for my motherboard then reboot again. Now press F8 to open windows boot menu and choose Safe Mode, the system should boot correctly.

Now simply reboot in standard mode and everything should work correctly. At least it worked in my system.

Gian Maria.

No comments

In the Update 3, now in RC, you have the ability to configure your Release Management to directly access your Azure Subscription to have a list of all of your environment. The operation is really simple, you need to go to Administration tab and then choose to Manage Azure.

image

Figure 1: Adding your subscription to Release Management

Adding a new Subscription is just a matter to enter some information taken from a valid publish certificate. If you have not available a valid certificate, the easiest way to obtain a new one is going to this url https://windows.azure.com/download/publishprofile.aspx. Once authenticated a new management certificate will be downloaded. Please do not abuse this functionality, or you will end with a lot of certificates.

Once you have downloaded a valid certificate, it contains everything you need to connect your azure subscription to Release Management. You need to copy your subscription Id and your management certificate.

image

Figure 2: Copy data from your management certificate

If you installed the CTP preview of Update3 you can notice that now you have another field to fill, called Storage Account Name. You need to copy a name of one valid account storage from your azure management account.

image

Figure 3: Copy all the info from your certificate and account to Release Management.

Now you need to wait some minutes, because the sync is done by a service that runs in the background that periodically check for availability of environments. If no machine shows up after few minutes, please check the Event Viewer of the machine where Release Management Server is running and try to restart the service called Release Management Monitor.

Once the service is able to synchronize with your account you should see all of your Azure VMs now available as servers inside release management.

image

Figure 4: All of your Azure Virtual Machines are now available in the Servers list.

If you installed the Deployer Agent to some of the VM those machines are listed with a Deployer Status of Ready, all of the other machines have a Deployer Status of Offline, because no Deployer Agent is present on those machines. Machines that have no Deployer Agent deployed can be used as target of deployment using powershell DSC.

Actually Release Management load information for every VM in your account, even Linux machines. This is not weird because if you missed it, actually PowerShell DSC is being ported to Linux as you can read from this article: Announcing Windows PowerShell Desired State Configuration for Linux.

Gian Maria.

Tags:

No comments