Azure-pipelines-tasks: Docker use private NuGet Feed

Created on 3 Jan 2018  ·  78Comments  ·  Source: microsoft/azure-pipelines-tasks

Environment

  • VSTS

Issue Description

When building docker containers I would like to be able to use private NuGet feeds hosted on VSTS (Packaging). Currently there does not seem to be a good way to do this other than including a NuGet.config file with clear text credentials, which is less than optimal.

The .NET core task (v4) has options for NuGet feeds, and it would be nice if the Docker containers worked the same.

ArtifactsPackages

Most helpful comment

What worked for me... using the PAT token.

My dockerfile:

FROM microsoft/aspnetcore-build:latest AS build
WORKDIR /src
COPY . .
COPY NuGet.Config ./
RUN dir
RUN dotnet restore --configfile NuGet.Config -nowarn:msb3202,nu1503 --verbosity diag
RUN dotnet publish --output /output --configuration Release

FROM microsoft/aspnetcore:latest
WORKDIR /app
COPY --from=build /output /app
ENTRYPOINT ["dotnet", "DockerProject.dll"]

and my NuGet.Config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="BredasVSTS" value="https://xxxx.pkgs.visualstudio.com/_packaging/BredasVSTS/nuget/v3/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <BredasVSTS>
      <add key="Username" value="emailhere" />      
      <add key="ClearTextPassword" value="PAT here" />
    </BredasVSTS>
  </packageSourceCredentials>
</configuration>

The Username parameter need to be passed but you can set a random username/phrase there... since PAT does not have username parameter.
Make sure that the nuget package have permissions (read and write) of PAT owner.

All 78 comments

Are you building the container using 'docker build'?

Yes, using the Dockerfile generated by Visual Studio, and the VSTS build template, Container (PREVIEW).

You can't use docker build for anything that has secrets (via files, envvars etc...) because the secret will end up being in the docker container you produce.

Instead, build the product including getting dev dependencies from nuget (that could also be in a container) to a mapped output container and then when you do docker build use a COPY statement in the docker build script.

We are working on first class docker support in VSTS which means you can say step 1 runs in container x and then run docker build.

If you email me at bryanmac (and that's at microsoft) I can share more details.

I believe that's what my Dockerfile is currently doing, although it's using a multi-stage build.

FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 80

FROM microsoft/aspnetcore-build:2.0 AS build
WORKDIR /src
COPY *.sln ./
COPY NuGet.config ./
COPY Devices/Devices.csproj Devices/
RUN dotnet restore
COPY . .
WORKDIR /src/Devices
RUN dotnet build -c Release -o /app

FROM build AS publish
RUN dotnet publish -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Devices.dll"]

Which is building correctly and the NuGet.config credentials are only accessible inside the build container which gets thrown away. I'm not particularly happy about including the credentials inside the repository but I guess that could be solved by creating the NuGet.config file inside the Agent using a shell script.

@Hinton - you're doing the dotnet restore in the docker file. You're also copying the nuget.config. What I'm saying is you do the dotnet restore and dotnet build outside the docker build file. The docker build file would copy in the resultant full product layout bits (your output).

... that also has the benefit of not requiring build tools in your products final container (small as possible). You can have a docker dev image that is based on the prod image and only the dev image has dev tools.

@bryanmacfarlane I understand that's a potential way to solve it. Docker build would then only copy the pre-built binary files and not actually build anything.

However Visual Studio Docker Tools would then no longer be able to build and debug it through Visual Studio as a Docker target. Seems like Visual Studio Docker Tools still works without the build step.

The Dockerfile above is the recommended way to build an asp.net core 2.0 container. From my understanding of docker multi-step build, only the last FROM command is saved as the final container. The resulting container only contains the binary files based on the aspnetcore image (not aspnetcore-build).

@bryanmacfarlane Your proposal is antithetical to the promise of multi-stage build and to some degree to Docker itself. The promise of consistent and predictable execution environments applies nicely to build/CI environments as well.

On the question, I don't think we've got a great solution for this currently. Ideally, you could specify a nuget.config via an environment variable. I don't think this will work w/o getting NuGet to become secret aware. I'll ask.

@richlander I agree with you. @bryanmacfarlane One of the big advantages of docker is being able to have a new developer build the solution with no prereqs installed except docker. In this way, they don't even need .NET core installed to build a .NET application. Also, @Hinton is correct in a multi-stage build only the last build stage is kept so, the build stage along with any secrets and/or SDK and build tools will not end up in the final docker image produced for your application.

@Hinton , @richlander, and @AceHack - I see where you're coming from. In VSTS we happen to have a focus on using containers for deployments. As such, we wanted to make sure you weren't putting VSTS PATs inside your deployments - and you're not! ✔️

It makes sense that you're asking for a better solution for the reproducible build scenario. We're chatting with @AndyGerlicher about this.

@jerickmsft That's great to hear, I've worked up my own solution for passing though tokens to do authenticate with the registry. I'm now working on, unit tests and getting the results into VSTS, integration tests, code coverage, performance profiling, running static analysis, white source, and the list goes on and on. Doing your build inside the docker container makes many of the VSTS tasks hard or impossible to use. I'm having to come up with my own solutions to all of these. It's not really possible to find any guidance on these subjects either. Thanks.

Hi All,

I was wondering if there has been any progress on allowing a VSTS private NuGet package feed to be read from the dockerfile build process? I've tried creating a nuget.config file that can be then read by the dockerfile COPY nuget.config /root/.nuget/NuGet/ which is created at build time using a PAT token, but no success, still a 401 error.

Thanks.

What worked for me... using the PAT token.

My dockerfile:

FROM microsoft/aspnetcore-build:latest AS build
WORKDIR /src
COPY . .
COPY NuGet.Config ./
RUN dir
RUN dotnet restore --configfile NuGet.Config -nowarn:msb3202,nu1503 --verbosity diag
RUN dotnet publish --output /output --configuration Release

FROM microsoft/aspnetcore:latest
WORKDIR /app
COPY --from=build /output /app
ENTRYPOINT ["dotnet", "DockerProject.dll"]

and my NuGet.Config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="BredasVSTS" value="https://xxxx.pkgs.visualstudio.com/_packaging/BredasVSTS/nuget/v3/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <BredasVSTS>
      <add key="Username" value="emailhere" />      
      <add key="ClearTextPassword" value="PAT here" />
    </BredasVSTS>
  </packageSourceCredentials>
</configuration>

The Username parameter need to be passed but you can set a random username/phrase there... since PAT does not have username parameter.
Make sure that the nuget package have permissions (read and write) of PAT owner.

@danilobreda - is your PAT token now in a layer of your docker container?

@AceHack - regarding building in container and dependencies - agreed. Both solutions build in a container. Building in a container is great for dev == dev == ci. It's awesome.

Regarding tasks and the CI solution still working (tasks etc... ) and secrets not getting into layers (maps work dirs into container outside in), we will be previewing the ability to run any phase in a container (full yaml and task fidelty).

https://github.com/Microsoft/vsts-agent/blob/master/docs/preview/yamlgettingstarted-phase.md#container-applies-to-queue

We're waiting on the rollout of a couple new hosted pools optimized for building containers. This and this.

I'm not advocating one over the other and docker build is an option. I'm just providing options while making it clear there's pros and cons to different approaches. Be aware of them. Pushing an image to a public repo with a token or cred in the layers is a real problem and concern.

We also have using kubernetes as a build pool (infra) in proof of concept phase working end to end.

@bryanmacfarlane

yes, it's because I'm not removing NuGet.Config, if I remove it, it will not be in any of the layers. Thank you for this note.

After some tests, its not on layers... the final docker is on the /output folder. It have only the "publish" output.

@danilobreda - one other note - does your current approach require you to check in your PAT to source code? (or some other process is generating it host side?)

Since this issue is getting some activity again, I figured it might be worthwhile to describe, more in-depth how we worked around the issue (for now).

In our build definitions, before the docker tasks we have a bash task, which creates a NuGet.config file from a secret variable.

steps:
- bash: 'echo -e ''$(NuGet.config)' > NuGet.config' 
  displayName: Create NuGet.config

The secret variable is linked through a variable group to our built tasks and contains the complete NuGet.config file with the PAT.

This ensures the NuGet.config files with credentials are not stored in the source repositories. (And as previously discussed, the configs are not leaked to the final image)

Note that this works using the linux agents, on windows the bash script should be replaced with a PowerShell equivalent.

For private nuget package or packages on Disk, I have the next Nuget.Config and Docker File. This works for me.

? xml version="1.0" encoding="utf-8" ?>
< configuration >
< packageSources >
< add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
< add key="AngryBirds" value="NugetPackage/" /> Local patch here
< /packageSources>
< packageRestore>
< add key="enabled" value="True" / >
< add key="automatic" value="True" / >
< /packageRestore>
< bindingRedirects>
< add key="skip" value="False" / >
< / bindingRedirects >
< packageManagement >
< add key="format" value="0" / >
< add key="disabled" value="False" / >
< /packageManagement>
< /configuration >

`FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 80

FROM microsoft/aspnetcore-build:2.0 AS build
WORKDIR /src

COPY NuGet.Config ./
COPY /NugetPackage/travelExpensesRestClient.1.0.0.nupkg NugetPackage/
RUN dir /src/NugetPackage

WORKDIR /src

COPY %AppData%\NuGet ./

COPY travelExpenseLiquidador.sln ./
COPY travelExpense.Liquidador/travelExpense.Api.Liquidador.csproj travelExpense.Liquidador/
COPY travelExpense.Model.Peticiones/travelExpense.Model.Liquidador.csproj travelExpense.Model.Peticiones/
COPY travelExpense.DALC.Liquidador/travelExpense.DALC.Liquidador.csproj travelExpense.DALC.Liquidador/
COPY travelExpense.BO.Liquidador/travelExpense.BO.Liquidador.csproj travelExpense.BO.Liquidador/

RUN dotnet restore -nowarn:msb3202,nu1503

RUN dotnet restore --configfile NuGet.Config -nowarn:msb3202,nu1503 #--verbosity diag
COPY . .
WORKDIR /src/travelExpense.Liquidador
RUN dotnet build -c Release -o /app

FROM build AS publish
RUN dotnet publish -c Release -o /app

Try to create image from Publish output

COPY / /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "travelExpense.Api.Liquidador.dll"]
`

@bryanmacfarlane ho, its on the code.. yes you are right.
I tried to use the Secure Files of the vsts, but i cant access it from the build container.

I think we can set the PAT as a enviroment variable... and pass it with the dockerfile ARG and ENV. Its something to test.

@danilobreda - yeah, that's what the yaml feature I pointed to above does. It gets source in the host and maps it into the container we spawn, then exec tasks in the container. That would allow you to use Secure Files and all other tasks. You also wouldn't need to copy it into the container or remember to delete. That needs a good dev == dev solution though.

Not sure, but I believe if you use ENV, that can get sealed in a layer. Might have to use ARG.

I have a Nuget custom task that adds the builds access token to the config. That way the token only lives for the life of the build and you don't have to worry about storing it in clear text in the config. Another nice thing is you don't need to remember to replace an expiring PAT.

image

sources Add -Name "MyPackages" -Source "https://my.pkgs.visualstudio.com/_packaging/MyPackages/nuget/v3/index.json" -username any -password $(System.AccessToken) -ConfigFile Source/Nuget.config -StorePasswordInClearText

Make sure that you also have"Allow scripts to access OAuth token" checked on the options tab.

I'm happy with this as a placeholder a better solution is presented.

Looks like this will be a reality soon-ish :)
https://github.com/docker/cli/pull/1288

Just requires BuildKit to be enabled, which is possible from Docker 18.06-CE.

"--secret" won't be supported on 18.06 daemons though, the version of buildkit
included with it doesn't have what is needed to make that work.

@cpuguy83 Sorry for the confusion. Meant that BuildKit's included (experimentally) since 18.06.

Looking at the PR --secret will likely be in 18.09, right?

Correct.

So it will be possible to pass the PAT as a secret? How it will help for Docker use private NuGet Feed, can somebody clarify? Thanks.

Same Problem here
error

My Nuget.Config

`


























`

Docker File
`FROM microsoft/dotnet:sdk AS build-env
WORKDIR /app
EXPOSE 80

Copy csproj and restore as distinct layers

COPY *.csproj ./
COPY . /app

COPY Nuget.config Nuget.config ./

RUN dotnet restore --configfile Nuget.config

RUN dotnet restore

Copy everything else and build

COPY . /app
COPY . ./
RUN dotnet publish -c Release -o out

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Service.dll"]
`
Can somebody clarify my mistake.Thanks

I have a Nuget custom task that adds the builds access token to the config. That way the token only lives for the life of the build and you don't have to worry about storing it in clear text in the config. Another nice thing is you don't need to remember to replace an expiring PAT.

image

sources Add -Name "MyPackages" -Source "https://my.pkgs.visualstudio.com/_packaging/MyPackages/nuget/v3/index.json" -username any -password $(System.AccessToken) -ConfigFile Source/Nuget.config -StorePasswordInClearText

Make sure that you also have"Allow scripts to access OAuth token" checked on the options tab.

I'm happy with this as a placeholder a better solution is presented.

Unfortunately this does not work on Linux build agents.
https://developercommunity.visualstudio.com/content/problem/215823/issues-trying-to-build-docker-linux-image-in-vsts.html

@Fredrik-C - you may want to start a separate issue. But

Make sure that you also have"Allow scripts to access OAuth token" checked on the options tab.

Tasks always get the per build bearer token. That checkbox was intended for ad-hoc scripts (sh, ps1, etc)

For Linux, Try Hosted Ubuntu 1604 just released. The preview one will be going away

You can use this yaml to run your build in a container on ubuntu 1604: https://github.com/Microsoft/azure-pipelines-agent/blob/master/docs/preview/yamlgettingstarted-containers.md

@Fredrik-C , Not sure why you are having that issue. I use hosted Linux build agents.

@bryanmacfarlane , If I don't have that box checked, my Nuget restore fails with a 401.

We dont use the Hosted Linux agents since our target machines are within an
isolated Azure ASE.

So I guess I need to ask our infra guys to upgrade the Linux agents.

On Fri, 14 Sep 2018, 20:45 Chris Woolum, notifications@github.com wrote:

@Fredrik-C https://github.com/Fredrik-C , Not sure why you are having
that issue. I use hosted Linux build agents.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Microsoft/vsts-tasks/issues/6135#issuecomment-421450109,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AH9w1svBoYd2stbuJGktr52vt6URCa9wks5ua_lQgaJpZM4RR0BY
.

@cwoolum - are you scripting or cli use of nuget or is it the nuget task? (tasks authors get access to the token, ad-hoc scripts need to check the box)

We use "RUN dotnet restore" i the Dockerfile for the build phase/container.

On Sat, 15 Sep 2018, 14:06 Bryan MacFarlane, notifications@github.com
wrote:

@cwoolum https://github.com/cwoolum - are you scripting or cli use of
nuget or is it the nuget task? (tasks authors get access to the token,
ad-hoc scripts need to check the box)


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Microsoft/vsts-tasks/issues/6135#issuecomment-421559318,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AH9w1nnY4omzxR2xZ9iMyLzoyScaFrudks5ubO0ugaJpZM4RR0BY
.

@bryanmacfarlane , If I don't have that box checked, my Nuget restore fails with a 401.

Where is this box ? If I look under "Options" I don't see that ,please upload a screenshot I have been facing 401 problems too with Docker and a private Nuget feed if there is a workaround I need it urgently thanks a million.

image

[[[ Edit ]]]
Ok it's "Additional Options" not simply "Options" and located on the Agent Job settings page

image

[[[[ further edit ]]]

after ticking the oath box and doing it again it seems I still get the same result 401 so I cannot fetch the secret (or variable containing a secret) from the VSTS build options into the docker

While I try to read the PAT this way using a variable the dotnet restore doesn't allow the use of API key to restore only to push ?

What can we do here other than shifting the code and packages to a private server on AWS ?

Is docker compatible with private nuget if so what is the approach?

image

ARG NUGET_KEY=$vsts_token

I have a Nuget custom task that adds the builds access token to the config. That way the token only lives for the life of the build and you don't have to worry about storing it in clear text in the config. Another nice thing is you don't need to remember to replace an expiring PAT.

image

sources Add -Name "MyPackages" -Source "https://my.pkgs.visualstudio.com/_packaging/MyPackages/nuget/v3/index.json" -username any -password $(System.AccessToken) -ConfigFile Source/Nuget.config -StorePasswordInClearText

Make sure that you also have"Allow scripts to access OAuth token" checked on the options tab.

I'm happy with this as a placeholder a better solution is presented.

Hi where is this placeholder workaround ? Which is the options screen mentioned ? Can you clarify ? I just joined a new job and they are hitting this issue with 401 (or using public VSTS agents which are just too slow and not being used)

@Fredrik-C - you may want to start a separate issue. But

Make sure that you also have"Allow scripts to access OAuth token" checked on the options tab.

Tasks always get the per build bearer token. That checkbox was intended for ad-hoc scripts (sh, ps1, etc)

For Linux, Try Hosted Ubuntu 1604 just released. The preview one will be going away

You can use this yaml to run your build in a container on ubuntu 1604: https://github.com/Microsoft/azure-pipelines-agent/blob/master/docs/preview/yamlgettingstarted-containers.md

The link goes to a 404 ?

@infiniteodovel, you can set it on the phase.

image

image

@infiniteodovel, you can set it on the phase.

image

image

cool yes thanks I found that but still getting 401
What else did you do to get a dotnet restore from private nuget inside your docker ?
Also where exactly did you store the nuget.config ? thanks a million.

Olivier

I copy it into my container and then run RUN dotnet restore --configfile ../Nuget.config -nowarn:msb3202,nu1503 in the project folder.

@cwoolum Be careful though, because now your key is in on of your image’s layers. Even with multi-stage builds it’s a pretty dicey road.

The token is only valid for the lifetime of the build. The only way anyone could use it is if they somehow managed to grab the image while the build is still running.

While that’s true, it still doesn’t feel like the best way this should be achieved. But it might be a good way with current limitations.

Exactly, as I say above, I'm happy with this as a placeholder a better solution is presented.

I copy it into my container and then run RUN dotnet restore --configfile ../Nuget.config -nowarn:msb3202,nu1503 in the project folder.

Awesome thanks for shedding the light on my newbie question.

Hello,

interesting that this issue is still not worked out.

Here is what I'm using right now, and I guess based on the reading from above that the given solution solves following problems:

  • no secret (PAT) is shared within a docker image even not in layers between.
  • no secret must be kept in variables
  • build and publish the app within docker remains (is not affecting the docker build environment)
  • local development configuration can be identical (at least regarding restore packages)

The steps are the following:

  • In the docker file define arguments to pass downloaded nuget files.
  • Extend the restore command with a --source flag with given nuget downloaded folder.
  • In DevOps create a pre step task to download nuget's from a secured nuget feed.
  • In DevOps in the docker build task provide the folder with downloaded nuget's.

The example builds a dotnet core application and create an docker image.

image

Here is a YAML definition for a DevOps pipeline:

YAML

resources:
- repo: self
 
queue:
  name: Hosted Linux Preview
 
variables:
  nugets: '.nugets/'
 
steps:
- task: DotNetCoreCLI@2
  displayName: Restore
 
  inputs:
    command: restore
    projects: '$(Parameters.RestoreBuildProjects)'
    vstsFeed: 'YOUR SECURE NUGET FEED'
    restoreDirectory: '$(System.DefaultWorkingDirectory)/$(nugets)'
    verbosityRestore: Normal
 
- task: Docker@1
  displayName: 'Build an image'
 
  inputs:
    azureSubscriptionEndpoint: 'YOUR AZURE SUBSCRIPTION ID'
    azureContainerRegistry: YOUR AZURE CONTAINER REGISTRY
    dockerFile: DockerConsole/Dockerfile
    arguments: '--build-arg source="$(nugets)"'
    useDefaultContext: false
    buildContext: '$(System.DefaultWorkingDirectory)'

Here is an example docker file:

Dockerfile

FROM microsoft/dotnet:2.1-sdk as base
ARG source
COPY ["SOME_DIRECTORY/YOUR_APPLICATION.csproj", "SOME_DIRECTORY/"]
COPY /$source .nugets
RUN dotnet restore "SOME_DIRECTORY/YOUR_APPLICATION.csproj" --source ".nugets"
COPY . .
RUN dotnet publish SOME_DIRECTORY/YOUR_APPLICATION.csproj -c Release -o /app
WORKDIR /app
ENTRYPOINT ["dotnet", "YOUR_APPLICATION.dll"]

enjoy happy building ;)

This seems like a pretty common scenario and the issue has been open for 10 months. Is there a best practice recommendation on how to solve this problem? I want to make sure the solution builds/runs both locally in Visual Studio and also in Azure DevOps pipeline.

I finally found a solution that I'm happy with! There's a new lib called Microsoft/artifacts-credprovider. It's a plugin for Nuget that allowed you to authenticate to private repos from the command line. Another nice feature it has is that you can pass in a Nuget source configuration using an environment variable.

ARG PAT

RUN apt-get update && apt-get install -y locales
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
ENV LANG en_US.UTF-8

RUN wget -qO- https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh | bash

WORKDIR /app

COPY ./*.sln ./Nuget.config ./*.props ./*.targets ./
COPY src/*/*.csproj ./
RUN for file in $(ls *.csproj); do mkdir -p src/${file%.*}/ && mv $file src/${file%.*}/; done

ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS {\"endpointCredentials\": [{\"endpoint\":\"https://myfeed.pkgs.visualstudio.com/_packaging/MyPackages/nuget/v3/index.json\", \"username\":\"build\", \"password\":\"${PAT}\"}]}

RUN dotnet restore --configfile Nuget.config *.sln

When you build your image, just add the --build-arg PAT=$(System.AccessToken) parameter.

The nice thing about this solution is that the ARG changing doesn't invalidate your hash so you can cache the entire dotnet restore step as long as your csproj files don't change.

Modifying docker file like mentioned here would work , https://stackoverflow.com/questions/48821991/dockerfile-cant-see-local-file-or-private-nuget-server/54017310#54017310

only flaw here is , you would need to provide credentials for private repo in nuget.config

@cwoolum thank you for this snippet, it works.
Just a reminder for those who still get 401 even after applying @cwoolum solution, your PAT token needs to have Packages read permission included in their scopes.

@cwoolum thank you for this snippet, it works.
Just a reminder for those who still get 401 even after applying @cwoolum solution, your PAT token needs to have Packages read permission included in their scopes.

Where can I configure the read permission? How can I know which PAT is being used?

Seriously, when is this going to be fixed? I've done ALL the different solutions in this discussion and anything works! When is this going to be fixed? I've been blocked for the last 3 weeks.

@JerrySantana92 On Azure Devops click on your account and then security. There your token needs to have Agent pools (read & manage), Deployment Groups (read & manage) and Packaging (read).

PAT token is then passed as an argument as shown on screenshot.
$(System.AzureDevopsAccessToken) is a variable with your token from your account.
image

The solution posted by @cwoolum seems to best solution I've encountered so far. Documentation on this scenario is VERY lacking. It seems like either the Azure Pipelines or Azure Artifacts docs should contain an example of the cross platform friendly way to do a package restore from a private Azure Artifacts feed from within a docker container. I wasted LOTS of time trying to get to this solution and we're still left wondering if this is the "best" or "recommended" approach (I suspect it is).

@JerrySantana92 On Azure Devops click on your account and then security. There your token needs to have Agent pools (read & manage), Deployment Groups (read & manage) and Packaging (read).

PAT token is then passed as an argument as shown on screenshot.
$(System.AzureDevopsAccessToken) is a variable with your token from your account.
image

I've done that and still getting Unauthorized. Anything works for me.. this should be a bug in the task or pipeline.

The nice thing about this solution is that the ARG changing doesn't invalidate your hash so you can cache the entire dotnet restore step as long as your csproj files don't change.

@cwoolum Unfortunately, changing the value of an ARG does cause a cache miss on the first use of that variable, causing the rest of the image to be rebuilt (including the dotnet restore), see Dockerfile reference.

Using Docker build secrets, I was finally able to come up with a solution that properly handles caching and is also secure. Check out my blog post on it

https://medium.com/@cwoolum/using-nuget-restore-securely-inside-of-docker-containers-with-caching-2c2f5453905d

This solution doesn't work with Docker Compose yet and requires at least Docker 18.09 to work.

@cwoolum Really nice! The buildx plugin, which is available in the current 19.03 betas can also build compose files via BuildKit, which means it also has support for mounting secrets and caches. It works via the ‘docker buildx bake’ command.

Buildkit support in docker-compose depends on https://github.com/docker/docker-py/issues/2230, which probably won’t be fixed in 19.03.

I may have misunderstood something, but none of these solutions seem to work for using Docker from Visual Studio with Windows-based containers, right?

apt-get would be out because of Linux, using Azure DevOps tasks is out because this wouldn't work inside Visual Studio and using Visual Studio project modifications like DockerfileBuildArguments don't seem to allow dynamic replacements like environment variables, only static text (which would commit the secret into the repo).

As of yet, I did not find a solution to use a .NET Core project with Windows-based Docker containers that allow running via F5 from inside Visual Studio. Am I missing something?

In Visual Studio, I've noticed that the build tools don't use the entire Dockerfile so restore works when building in Visual Studio. From what I can tell, it only uses the base image or the first few lines but I'm not positive on that. I've never had issues with F5 just working for Docker containers, no matter what Dockerfile I've had.

For making this work in a deployed environment, artifacts-credprovider does work on windows and you should be able to use the steps to install it to get it added as part of your image. From there, you should be able to use the same environment variable to authenticate. Just make sure that you are using a Windows Build host in Azure Pipelines so it can build Windows containers.

I found this blog post really helpful and I take no credit for the solution. https://blog.ehn.nu/2019/05/accessing-azure-artifacts-feed-in-a-docker-build/

A workaround is to add a step in your dockerfile to download the microsoft azure cred provider and you pass your PAT as a build arg to docker.

docker build . --build-arg PAT=<pat-token>

# Dockerfile step
# Install Credential Provider and set env variables to enable Nuget restore with auth
ARG PAT
RUN wget -qO- https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh | bash
ENV NUGET_CREDENTIALPROVIDER_SESSIONTOKENCACHE_ENABLED true
ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS "{\"endpointCredentials\": [{\"endpoint\":\"<PRIVATE_ARTIFACT_FEED_HERE>\", \"password\":\"${PAT}\"}]}"

https://dev.azure.com/jakob/ignitetour/_git/DockerBuilds?path=%2F4.%20NugetRestore%2FWebApplication1%2FDockerfile&version=GBmaster

The info provided by @heratyian works perfectly for me and is easy to implement.

We already have that solution above but it prevents the dotnet restore step from being cached by docker.

@cwoolum I see you're other post about getting docker to cache with build secrets, I'll give that a whirl. There is a lot of info to parse in this thread!

I've come up with another way to use private Nuget repos in Azure Pipelines builds. It uses service containers so you'll need to be able to use YAML builds to support it.

The BuildKit solution I had above worked but you lost the ability to use --cache-from which is crucial to keeping build times down on Azure hosted agents. This new approach loads up a Nuget proxy in a container using your builds' access token to authorize and maps it to port 8080. From within your Dockerfile, you can restore using the host IP as a Nuget server. This eliminates the PAT arg which breaks the cache.

See the repo with the proxy and an example at https://github.com/cwoolum/ThinNugetProxy.

What worked for me... using the PAT token.

My dockerfile:

FROM microsoft/aspnetcore-build:latest AS build
WORKDIR /src
COPY . .
COPY NuGet.Config ./
RUN dir
RUN dotnet restore --configfile NuGet.Config -nowarn:msb3202,nu1503 --verbosity diag
RUN dotnet publish --output /output --configuration Release

FROM microsoft/aspnetcore:latest
WORKDIR /app
COPY --from=build /output /app
ENTRYPOINT ["dotnet", "DockerProject.dll"]

and my NuGet.Config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="BredasVSTS" value="https://xxxx.pkgs.visualstudio.com/_packaging/BredasVSTS/nuget/v3/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <BredasVSTS>
      <add key="Username" value="emailhere" />      
      <add key="ClearTextPassword" value="PAT here" />
    </BredasVSTS>
  </packageSourceCredentials>
</configuration>

The Username parameter need to be passed but you can set a random username/phrase there... since PAT does not have username parameter.
Make sure that the nuget package have permissions (read and write) of PAT owner.

Thanks! This worked for me. Regards!

This is normal. When you request your packages from the Azure Artifacts
source, Azure Artifacts will look upstream at Nuget.org and cache the
packages.

You can remove Nuget.org as an upstream source but then you'll need to
ensure your nuget config in your solution has that source and your Azure
Artifacts source so it can search both.

On Tue, Mar 24, 2020 at 6:43 AM andrew-vdb notifications@github.com wrote:

By doing this, it will push ALL dependencies to azure artifacts

[image: image]
https://user-images.githubusercontent.com/12871379/77431837-8c768900-6ddd-11ea-99a4-f74bb09855cf.png

[image: image]
https://user-images.githubusercontent.com/12871379/77431913-aa43ee00-6ddd-11ea-93e3-cd4700e9c45d.png

Is this normal? expected?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/microsoft/azure-pipelines-tasks/issues/6135#issuecomment-603246103,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAHGCT6TT24JLTRG4QOT66TRJC2GJANCNFSM4EKHIBMA
.

@cwoolum Thanks for the reply, I already deleted my post... For anyone else, I was asking why the nuget.org packages being copied to my azure private nuget feed

Another problem now, for local development, regular container development mode, for build pipeline we use $(System.AccessToken)
What do we do with local development? at this moment I put my own PAT
image
I can't share this with others

Update:
I put my own PAT within this file now, .csproj.user
image

Is there any better way than this?

You wouldn't put that config in your project file. In Visual Studio 2019,
you would already be authenticated via your account. For your builds, you
would pass the PAT as a task parameter in your docker or docker-compose
build step. See my posts above for more details. At no point should you
need to specify the PAT manually.

On Tue, Mar 24, 2020 at 11:13 PM andrew-vdb notifications@github.com
wrote:

@cwoolum https://github.com/cwoolum Thanks for the reply, I already
deleted my post... For anyone else, I was asking why the nuget.org
packages being copied to my azure private nuget feed

Another problem now, for local development, regular container
development mode
, for build pipeline we use $(System.AccessToken)
What do we do with local development? at this moment I put my own PAT
[image: image]
https://user-images.githubusercontent.com/12871379/77505326-1e74a500-6e63-11ea-9615-1dd5ae3ea048.png
I can't share this with others

Update:
I put my own PAT within this file now, .csproj.user
[image: image]
https://user-images.githubusercontent.com/12871379/77506822-1a4a8680-6e67-11ea-9ee7-325320948013.png

Is there any better way than this?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/microsoft/azure-pipelines-tasks/issues/6135#issuecomment-603660502,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAHGCT6IOQRMAC34M7MTKUTRJGOHZANCNFSM4EKHIBMA
.

In Visual Studio, I've noticed that the build tools don't use the entire Dockerfile so restore works when building in Visual Studio. From what I can tell, it only uses the base image or the first few lines but I'm not positive on that. I've never had issues with F5 just working for Docker containers, no matter what Dockerfile I've had.

I believe you use fast mode, not regular mode....

Have folks seen Managing NuGet Credentials in Docker Scenarios? It seems closely related to this topic.

/cc @mthalman

It might be the same approach, but I prefer to use the dotnet cli to add the nuget source + credentials. Especially if you use a multi-stage build, the nuget config that stores the token is removed afterwards. There is no need to add a specific packages as i think. Especially if you run it Azure Pipelines you can just inject the $(System.AccessToken) as the PAT argument. It would look like this in the dockerfile

ARG PAT
COPY . .
RUN dotnet nuget add source "your-source-url" --name "source-name" --username "useless" --password "$PAT" --store-password-in-clear-text
RUN dotnet restore

As @richlander pointed out this is something to follow up on the dotnet-docker repo:
https://github.com/dotnet/dotnet-docker/blob/master/documentation/scenarios/nuget-credentials.md

Reading through so many solution and implementing them , i was huffed and puffed .

please don't forget to add username in ENV variable otherwise you will have 401.

ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS "{\"endpointCredentials\": [{\"endpoint\":\"https://something.pkgs.visualstudio.com/_packaging/Nuget/nuget/v3/index.json\", \"username\":\"build\", \"password\":\"${PAT}\"}]}"

My question is: How to make PAT safe when I also use docker-compose.yml to build the Dockerfile.

I'm trying this latest approach and the Docker build step isn't interpolating the variable usage for the build-args:

image

I tried the above with no quotes and single quotes as well.

Here is the important part of my Dockerfile:

image

And when I look at the logs of the failed build, I see that it is sending the password to my private source like this:

image

Reminder: Do NOT NOT NOT put secrets/credentials as ENV vars into layers that you ship. Docker loves to store your environment variables as part of the layer. If you are not careful you will ship your credentials with the layers you create.

See:
https://github.com/dotnet/dotnet-docker/blob/master/documentation/scenarios/nuget-credentials.md
https://medium.com/@cwoolum/using-nuget-restore-securely-inside-of-docker-containers-with-caching-2c2f5453905d

Was this page helpful?
0 / 5 - 0 ratings