Nexus Adventures

Coding Scenario: Work wants to create a secure pipeline for developing services and code. Computers are locked down so that they can not get dependencies off of the internet and should get the from a a verified place. My framework of choice is .NET 5, which means repository needs to be able to support nuget packages. Here is my story.

Versions tested

Software Version
Docker 20.10.5, build 55c4c88
Linux Mint 20 (Ulyana), Linux 5.4.0-26-generic
.NET SDK 5.0.201
Nexus OSS 3.30.0-01
Squid Proxy * 4.13

* this was a custom squid proxy that I created which can inject headers, normal squid should work properly.

Sonatype Nexus is an Open-Source Repository which runs on a number of Operating systems and can proxy act as a repo for many different dependency libraries, apt, npm, ruby-gems, maven etc.

I've installed mine on Linux on my simulated on-prem environment. (There's plenty of install howto's, I'm not going to go into the details).

What I did have a problem with was pointing my .NET Core code at the repo I'd created.

By default Nexus sets up a nuget proxy repository which you should be able to point code installs at.

Nexus Dashboard

If we click on the server and administration cog on the toolbar of the nexus website, we can see how each of the repositories is configured. I didn't do any changes there.

Cog > Repository > Repositories >

Nexus Repo Settings

The important part I was after was the URL:

When compiling .net core code, when you do a dotnet restore, the compile process reads the *.csproj file, looks at your dependencies list, see if you need to satisfy any of those dependencies, and if so download them. (I was doing this on my monolithsvc code base hosted here)

The repository it downloads the dependencies by default is called "nuget", and what we should be able to do is use the same command with an extra switch.

We have code, a repo to download dependencies and now to simulate a secure network. I spun up a new linux Mint box, installed Docker CE 20 and .NET 5.0. I wanted Nexus to be able to build assist in being able the creation of images, without my development box reaching out to the internet, to which I needed two base images from the internet before cutting off access to the internet

1docker pull
2docker pull
4docker tag 52af65d291e7 lin-nexus-001.local:8123/sdk
5docker tag 0678c0a71d53 lin-nexus-001.local:8123/aspnet

We'll create a hosted docker repo on the Nexus server with the following settings:

Nexus Docker Repo Settings

..and now point our Docker CE install on our development box to our nexus Repository (located at /etc/docker/daemon.json). I'm using insecure registries here to not have to worry about setting up TLS certificates, in the real world you would.

2    "insecure-registries" : [ "lin-nexus-001.local:8123" ],
3    "registry-mirrors": ["http://lin-nexus-001.local:8123"]

aah, one more thing that I found I had to enable to get the docker push to work was in Administration > Security > Realms add the Docker Bearer Token Realm to the active Realm

Nexus Active Realm Addition

Now push our tagged images from the development docker box to our Nexus Server

1docker login lin-nexus-001.local:8123 -u admin -p mysecretpassword
3docker push lin-nexus-001.local:8123/sdk
4docker push lin-nexus-001.local:8123/aspnet

Now we want to configure the network. I turned off IPv6, taking the default gateway and DNS settings out. Tested the connectivity the box, I could ping anything on my LAN by IP, but not or Secure dev box achieved. (Optional: we can configure nexus to use a secure proxy server as well to limit and audit its outbound network traffic too in the admin interface if we wanted to)

Application build config now, the DockerFile that we used to normally build our monolithsvc had to change to use the nexus hosted SDK and aspnet, and to change the nuget sources to point back to nexus too.

 1 # Sample contents of Dockerfile (another test)
 2 # Stage 1, image is locally tagged SDK
 3 FROM lin-nexus-001.local:8123/sdk:latest AS builder
 4 WORKDIR /source
 6 # caches restore result by copying csproj file separately
 7 COPY *.csproj .
 8 # changes here to change the repo source
 9 COPY nuget.config .
10 RUN dotnet nuget disable source
12 # normalcy resumes
13 RUN dotnet restore 
15 # copies the rest of your code
16 COPY . .
17 RUN find -type d -name bin -prune -exec rm -rf {} \; && find -type d -name obj -prune -exec rm -rf {} \;
18 RUN dotnet publish --output /app/ --configuration Release
20 # Stage 2
21 FROM lin-nexus-001.local:8123/aspnet:latest
22 WORKDIR /app
23 COPY --from=builder /app .
24 ENTRYPOINT ["dotnet", "monolithsvc.dll"]

...and we need a nuget.config file in our project as well (currently called in the repo so as to not impact my normal CI builds)

 1<?xml version="1.0" encoding="utf-8"?>
 3  <config>
 4  </config>
 5  <packageSources>
 6    <add key="lin-nexus-001" value="" />
 7  </packageSources>
 8  <packageSourceCredentials>
 9    <lin-nexus-001>
10      <add key="Username" value="testuser" />
11      <add key="ClearTextPassword" value="mysecretpassword" />
12    </lin-nexus-001>
13  </packageSourceCredentials>

deep breath. on the "secure" development box, from within the monolithsvc project folder where the DockerFile is defined.

 1docker build -f ./ -t lin-nexus-001.local:8123/mono:latest . 
 2Sending build context to Docker daemon  6.287MB
 3Step 1/13 : FROM lin-nexus-001.local:8123/sdk:latest AS builder
 4latest: Pulling from sdk
 5ac2522cc7269: Pull complete 
 69fa9d779e93d: Pull complete 
 72aae9807db0e: Pull complete 
 80328faf4c671: Pull complete 
 9fc31e29a4bfe: Pull complete 
10ab30c47fa842: Pull complete 
114eef46b595d9: Pull complete 
12f51b88edb9c8: Pull complete 
13Digest: sha256:e3f2ba64002adfe11e76e4b9b953c5e8316ab81407b4903c07ca7a5ec9104496
14Status: Downloaded newer image for lin-nexus-001.local:8123/sdk:latest
15 ---> 52af65d291e7
16Step 2/13 : WORKDIR /source
17 ---> Running in 0b764023abb9
18Removing intermediate container 0b764023abb9
19 ---> bf78678a767a
20Step 3/13 : COPY *.csproj .
21 ---> d34a462cf25b
22Step 4/13 : COPY ./nuget.config
23 ---> 1df88c12dd40
24Step 5/13 : RUN dotnet nuget disable source
25 ---> Running in e3de26f5f83c
26Package source with Name: disabled successfully.
27Removing intermediate container e3de26f5f83c
28 ---> a3802b7eb5ac
29Step 6/13 : RUN dotnet restore
30 ---> Running in 68b6c3d293cd
31  Determining projects to restore...
32  Restored /source/monolithsvc.csproj (in 48.61 sec).
33Removing intermediate container 68b6c3d293cd
34 ---> f4acfc4e35f1
35Step 7/13 : COPY . .
36 ---> daaaacb1522d
37Step 8/13 : RUN find -type d -name bin -prune -exec rm -rf {} \; && find -type d -name obj -prune -exec rm -rf {} \;
38 ---> Running in 0b3610458773
39Removing intermediate container 0b3610458773
40 ---> d3d63d495447
41Step 9/13 : RUN dotnet publish --output /app/ --configuration Release
42 ---> Running in b2be1e5bee09
43Microsoft (R) Build Engine version 16.9.0+57a23d249 for .NET
44Copyright (C) Microsoft Corporation. All rights reserved.
46  Determining projects to restore...
47  Restored /source/monolithsvc.csproj (in 386 ms).
48/source/Models/EnvironmentUtils.cs(33,32): warning SYSLIB0012: 'Assembly.CodeBase' is obsolete: 'Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location instead.' [/source/monolithsvc.csproj]
49  monolithsvc -> /source/bin/Release/net5.0/monolithsvc.dll
50  monolithsvc -> /source/bin/Release/net5.0/monolithsvc.Views.dll
51  monolithsvc -> /app/
52Removing intermediate container b2be1e5bee09
53 ---> e65054492951
54Step 10/13 : FROM lin-nexus-001.local:8123/aspnet:latest
55latest: Pulling from aspnet
56ac2522cc7269: Already exists 
579fa9d779e93d: Already exists 
582aae9807db0e: Already exists 
590328faf4c671: Already exists 
60fc31e29a4bfe: Already exists 
61Digest: sha256:c4886e7d885809d5e14b1ac552e415e034465846c9dbc869d276e4c9901270f3
62Status: Downloaded newer image for lin-nexus-001.local:8123/aspnet:latest
63 ---> 0678c0a71d53
64Step 11/13 : WORKDIR /app
65 ---> Running in ece1addb22a2
66Removing intermediate container ece1addb22a2
67 ---> 338e1f80ef1a
68Step 12/13 : COPY --from=builder /app .
69 ---> b617e695bcee
70Step 13/13 : ENTRYPOINT ["dotnet", "monolithsvc.dll"]
71 ---> Running in 9bc835179638
72Removing intermediate container 9bc835179638
73 ---> 26f1064cc01f
74Successfully built 26f1064cc01f
75Successfully tagged mono:latest

Now we just need a team of people to manage signing off each of the dependencies and making them available to the rest of the network.

and there we go. I will be uploading a video of this at some point in the very near future as there is a lot going on here!