Response status code does not indicate success: 401 (Unauthorized) - Azure Devops Feed ASP.NET Core 3.1 Docker Build

7.1k views Asked by At

I have found a few articles, and posts on this forum, relating to the issue of an Azure private artifact feeds not able to be authorized when building an image with the Docker build task in Azure, which is understandable.

So, I have put together a Dockerfile that mirrors the online examples:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src

EXPOSE 80

# The Personal Access Token arg
ARG NUGET_PAT

# Set environment variables
ENV NUGET_CREDENTIALPROVIDER_SESSIONTOKENCACHE_ENABLED true
ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS '{"endpointCredentials": [{"endpoint":"https://pkgs.dev.azure.com/MY_FEED/nuget/v3/index.json", "username":"username", "password":"${NUGET_PAT}"}]}'

# install wget
RUN apt-get update && apt-get install -y wget 

# Get and install the Artifact Credential provider
RUN wget -O - https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh  | bash

COPY ["xxx.csproj", "."]
RUN dotnet restore -s "https://pkgs.dev.azure.com/MY_FEED/nuget/v3/index.json" -s "https://api.nuget.org/v3/index.json"

COPY . .
WORKDIR "/src"
RUN dotnet build "xxx.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "xxx.csproj" -c Release -o /app/publish

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

Then in the build args textbox in Azure I have this:

NUGET_PAT=xxxxxxxxxxxxxxxxxxxxxxxxx

I have also set the PAT token to the following permissions as read in a post on this forum:

  • Build: Read
  • Connected server (Access endpoints): Connected server
  • Packaging (Create, read, update, and delete feeds and packages): Read

I have also set the PAT to allow all organizations as opposed to our working group, and I have tried copying a nuget.config directly into the container and all's I end up with is a 401 unauthorised.

I have also left the username set to "username" as most examples alluded to the fact that it wasn't required.

What am I doing wrong?

2

There are 2 answers

0
user1574598 On BEST ANSWER

Here is the final Dockerfile that works for me in the Azure pipeline with the Docker build and push tasks:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src

EXPOSE 80

# run the azure credential provider and let it do its magic
RUN curl -L https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh  | sh

# personal access token arg 
ARG NUGET_PAT

# link to azure feed arg
ARG AZURE_FEED

# set env var for azure credential provider
ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS \
    "{\"endpointCredentials\": [{\"endpoint\":\"${AZURE_FEED}\", \"username\":\"docker\", \"password\":\"${NUGET_PAT}\"}]}"

# debug env vars to make sure things are getting set correctly
RUN printenv

# restore private and public nuget feed
COPY ["xxx.csproj", "."]
RUN dotnet restore -s "${AZURE_FEED}" -s "https://api.nuget.org/v3/index.json"

# build
COPY . .
WORKDIR "/src"
RUN dotnet build "xxx.csproj" -c Release -o /app/build

# publish
FROM build AS publish
RUN dotnet publish "xxx.csproj" -c Release -o /app/publish

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

I also found that it was better to create a Variable Group in Azure with the AZURE_FEED and NUGET_PAT so the Personal Access Token and Feed can be shared amongst other pipelines.

10
Cece Dong - MSFT On

You may try the following format to see whether it works:

ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS "{\"endpointCredentials\": [{\"endpoint\":\"https://pkgs.dev.azure.com/org/_packaging/MY_FEED/nuget/v3/index.json\", \"password\":\"${NUGET_PAT}\"}]}"

And there is another alternative you may try, check the following blog for Solution 2:

https://medium.com/jtorrecilla-net/use-azure-artifacts-in-dotnet-restore-while-docker-build-7e017a439109

This solution is based on building a Nuget.Config file on the fly consuming the variables defined in the build process. For example:

Docker file:

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM microsoft/dotnet:2.2-sdk AS build
ARG ARTIFACTS_ENDPOINT
ARG ACCESS_TOKEN
ARG USER
WORKDIR /src
COPY / /src/Services/MyApi/
WORKDIR /src/Services/MyApi/
RUN echo "<?xml version='1.0' encoding='utf-8'?><configuration><packageSources><add key='MyFeed' value='$ARTIFACTS_ENDPOINT' /></packageSources><packageSourceCredentials><ByThey><add key='Username' value='$USER' /><add key='ClearTextPassword' value='$ACCESS_TOKEN' /></ByThey></packageSourceCredentials></configuration>" > NuGet.Config
RUN dotnet restore MyApi.csproj -nowarn:msb3202,nu1503

FROM build AS publish
RUN dotnet build MyApi.csproj --no-restore -c Release -o /app

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

CI yml file:

variables:
- group: Artifacts
steps:
- task: Docker@1
  displayName: 'Build an image'
  inputs:
    command: Build an image
    azureSubscription: Devops
    azureContainerRegistry: '{"loginServer":"xxx.azurecr.io", "id" : "/subscriptions/xxx/resourceGroups/xxx-DEV/providers/Microsoft.ContainerRegistry/registries/xxx"}'
    dockerFile: src/Services/MyApi/Dockerfile
    imageName: $(Build.Repository.Name):$(Build.BuildId)
    arguments: '--build-arg ARTIFACTS_ENDPOINT="$(artifactsEndpoint)" --build-arg ACCESS_TOKEN="$(artifactsAccessToken)" --build-arg USER="xxx"'