Once upon a time1, the company I work for decided to migrate all Docker images from a hosted registry to a self-hosted one. The main requirement, in line with the Principle of Least Privilege2, was to restrict service accounts to access only their designated images. This ensures that every project could only access its own images.
Since we were already using Nexus 3 as our private NPM registry, we decided to configure it for this use case as well. I had also configured something similar before, using the raw repository type. In the mentioned case, we published runnable JARs (builds per customer) to Nexus and allowed end users to download them with dedicated accounts4.
Setting up a new registry was straightforward, but restricting access to specific images required more effort - in fact a deeper understanding of Content Selectors5.
Steps and assumptions
The steps below assume that we have admin access to Nexus and a working Docker registry:
- Configure Content Selectors for login and image access.
- Create privileges based on the created Content Selectors.
- Create the role with new privileges and apply them to the user.
And that’s it! :-)
1. Configuring Content Selectors for Docker Login and accessing image
To achieve this, we need to configure Content Selectors5 that will allow us to:
- use the
docker login
command. - pull only the selected images (any tag).
To allow logging into the repo we will need the following content selector - it matches the path that is used by the docker login
command:
path == "/v2/"
So the content selector could look like this:
Apart from allowing us to log in, we need to allow access to selected images.
To allow all images in the following path we will use =^
6 to match all paths that start. Assuming that our image is sonatype/nexus3
then we need to create a selector:
path =^ "/v2/sonatype/nexus3"
Which translates to the following Content Selector:
We could merge both into the one with the or
operator.
Keeping them separate allows the first selector (for login) to be reused multiple times.
2. Creating privileges
As a next step, we need to create new privileges - each for the newly created content selector.
Both privileges should be configured for the read
action, as we only need read-only access.
In the screenshots below I select my Docker registry with the name docker
, but nothing stops us from selecting here (All docker repositories)
.
After that, we can go to the last step which is… creating a role and assigning it to our service account!
3. Creating the role and assigning it to the user
Now we will create the role (with type Nexus role
) and we will apply previously created privileges:
Then, cherry on the top, we will add that role to our service account:
That’s all. Now we can grab the login and password for our service account, log in and pull the images. Which is perfect for pulling images from the registry on the Kubernetes cluster. :-)
End notes
In a few steps, we have configured limited access to selected Docker images in our self-hosted registry. Even if that solution was nothing extraordinary, it allowed us to migrate from the hosted repository and have more control over image access.
Worth noting that it was a prerequisite to set up Nexus as a proxy in front of our GitLab instance - but this is the story for another time.
6 months ago, but in IT it is like decades, riiight? ↩︎
Principe Of Least Privilege means that the access shall be as limited as can be. ↩︎
Yes, Sonatype Nexus Repository OSS, as it is free to use and allows to store maven and NPM artifacts! ↩︎
raw
repository as we do not want to expose the Maven repo structure. In the end, we dropped that way of distribution as we moved to providing Docker images. ↩︎The documentation for Content Selectors can be found here ↩︎ ↩︎
That operator
=^
looks like an emoticon, isn’t it? ↩︎