Running a build in Azure DevOps with Cake and Azure Artifacts
What?
Azure Artifacts
Azure Artifacts can be seen as a private repository for your reusable assets (Nuget, NPM, Python, but also universal packages). The cool thing is thus that you can set up one (or more) private enterprise package feeds/repositories that facilitate you and your development teams in their daily work. The big benefit is that you do not (anymore) have to host a private artefact (such as proget or Nuget gallery) repo for yourself and that you are free from hosting and storage questions in that regard.
Microsoft offers this with a free amount of storage and prices for additional storage are very reasonable (you can't set up such a solution for yourself)!
The only thing that is different (compared to public repositories/registries/feeds/...), is that you have to account for authentication/authorization to these feeds/registries/... and that might cause you some headache, certainly in the context of Cake. When you start a cake build process, it is totally unaware of any security context that might exist in the build pipeline.
Edit: This post will also be very usefull when you are running into the error below (TF400813):
1message: "TF400813: The user '' is not authorized to access this resource.",
2npm WARN old lockfile typeName: 'Microsoft.TeamFoundation.Framework.Server.UnauthorizedRequestException, Microsoft.TeamFoundation.Framework.Server',
3npm WARN old lockfile typeKey: 'UnauthorizedRequestException',
4npm WARN old lockfile errorCode: 0,
5npm WARN old lockfile eventId: 3000
Security
Because of this security implication, I started looking around the internet for a good approach and found a lot of "tutorials"/opinions that suggested to work with a Personal Access Token .
In short, Personal Access Tokens (PAT) allow you to (let your tooling) interact with Azure DevOps. You can set up these tokens and give them an expiration date (how long are they valid?) ad a scope (what can they do?). It is a convenient, yet secure way, to work with the platform without needing to store your username/password somewhere
For local development, this is indeed a very interesting solution. What is important to understand though, is that anyone that gets your PAT into their possession can do literally anything that you set up this token for and that might be a big issue! So it is important to always treat your PAT as a password!!
Using a (personal) PAT in a build pipeline would therefore mean that anyone that has access to your build pipeline, would therefore have implicitly have access to your PAT (or to what you can do with it). In a context of (fraudulent) impersonation, this might not be a good idea... So, to me, this means that the approach of configuring (and using) a personal PAT in a build pipeline is not a good idea!
In my search to a good approach, I also discovered that the build process has a security context and that this security context works based on a pipeline specific PAT. In the build context, it is a predefined variable $(system.accesstoken) . The benefit of this approach is that you have a security context that is specific to this one build and if this token was to be leaked, it would only be valid for the duration of the build process.
The search
I started on a path to pass this variable to the cake process and to "generate my .npmrc
file on the fly", based on this token! I only could not get to a working solution...
Therefore, I contacted the Azure DevOps team via twitter and they told me that this was an approach that was not recommended as it (still) might be a cause for a security leak. They pointed me to the MS docs that explained the best practice, but I didn't find anything about running npm install
inside of Cake and that is why I was lost for a bit.
After a good night of sleep however, I read the documentation again and then I realized that I was approaching this completely different:
npm install
process. But that was a dead end as the Azure DevOps team recommended against this approach. (This makes sense as you might give other processes in the cake script access to stuff that they do not actually need) But what I did not yet think of, was the following: The only thing that you do need, is that your process, which talks to the artefact repo, knows how to authenticate to artefact registry.
That makes things a lot easier as you only need to prepare your "integration point" (eg: .npmrc
file) before starting your cake process. And this is functionality that is available "out of the box" in azure pipelines. (And to be honest, this was pointed out to me to by the Azure DevOps team, I just was to stubborn to see it ! 😃)
The solution
The solution to this "challenge" is thus quite easy. (You only need to think of it) All you need to do is add the npm/nuget/maven/python task and specify the correct file which has the reference to the artefact repo:
An example of the .npmrc
file" in your repo (next to your solution):
1registry=https://pkgs.dev.azure.com/<your org>/_packaging/<FeedName>/npm/registry/
and an example of the yml needed to activate the (in this case npm authenticate
task:
1- task: npmAuthenticate@0
2 inputs:
3 workingFile: '.npmrc'
During the execution of the task during the build process, the task will recognize your Azure Artifacts repo and add a security token for it.
in the context of our example, the npmrc
file would look something like this:
1registry=https://pkgs.dev.azure.com/<your org>/_packaging/<FeedName>/npm/registry/
2//pkgs.dev.azure.com/<your org>/_packaging/<FeedName>/npm/registry/:_authToken=<a very long token>
At this point, Cake will be able to run its script and (where needed) the cake sub processes that will need to talk to the artefact repo, will be able to do so and cake doesn't need to be aware of any security context! Also, at the end of the build process (after cake is finished), this task will also cleanup the .npmrc
file that was modified in the beginning, which is really nice!
Some points of consideration/attention:
- This should, apart from NPM, also work with the other technologies such as Nuget, maven and python
- When you still have authentication issues, then make sure that the build process has permissions to connect to the Azure Artifacts repo! (this can be set on the permissions tab of se feed settings in Azure Artifacts!)
- this also works with external registries that need authentication, but then you need to work with (and specify) a service connection
Conclusion
In this post I shared how you can set up your build pipelines in Azure DevOps so that you can run Cake and talk to the Azure Artifacts feeds. Please do refrain yourself from working with PAT's as there is a very interesting solution that you can use out of the box!
I hope it helps!
Posts in this Series
- Considerations when setting up a build (migration) strategy
- Running a build in Azure DevOps with Cake and Azure Artifacts
- Running Cake in Azure Pipelines and accounting for optional build-process-variables
- Automatically migrating your builds to Azure DevOps
- Extending build.cake with your (enterprise) functionality
- Dealing with error TF401019 when using submodules in Azure Pipelines
- Migrating your builds to TeamCity