Part of my daily routine involves managing the Sonatype Nexus Repository OSS, a free, hosted Sonatype Nexus Repository instance for hosting open source project repositories. There are more than 100 projects hosted on the OSS instance, and each project has at least one release repository, one snapshot repository, and one repository group. When we started offering this service I would create two repositories and a single repository group for each project, but as community adoption increased, I found that managing hundreds of repositories was become a very complicated and time-consuming task. In this post, I'm going to discuss how I consolidated hundreds of repositories down to a single release repository, snapshot repository, and repository group. I'm also going to discuss how I used Nexus security settings to partition these consolidated repositories, providing necessary isolation between separate projects.
If you are running a large instance of Sonatype Nexus Repository to manage internal development, or if you are responsible for an open source project's installation of Sonatype Nexus Repository, you can use the approach outlined in this post.
Each project controls a groupId
On the Sonatype Nexus Repository OSS instance, every project has a unique maven groupId. This groupId determines the repository path of all its artifacts. For example, all projects released by the ehcache project have a groupId of net.sf.ehcache. This means that all of the artifacts from the ehcache project are stored under the repository path /net/sf/ehceche. Take Plexus as another example, its maven groupId is org.codehaus.plexus, and its artifacts go under the repository path /org/codehaus/plexus. When projects have unique groupIds, there is no repository path collision. This means that we can consolidate hundreds of repositories into a single shared repository.
With a single, shared repository we need to find a way to provide isolation between each project (each groupId). Ehcache administrators should only be able to deploy artifacts to /net/sf/ehcache, and Plexus developers should only be able to deploy artifacts to /org/codehaus/plexus. Administrators should be given CRUD privileges on a project's repository path, other users are only allowed to read this path.
Implement partitioning
To implement this partitioning, I use Nexus Repository Targets, Privileges, and a custom Nexus Role. Let's take a look at the Ehcache groupId and walk through the process of creating a repository target for the ehcache repository path, a set of privileges that grant CRUD access to this area of the repository, and an Ehcache Admin role.
Step 1: Create a repository target
To create a repository target, click on Repository Targets under the Administration section of the Sonatype Nexus Repository application menu. Once you click on Repository Targets, click on the Add button above the list of repository targets. The groupId of Ehcache is net.sf.ehcache. In the following figure I'm creating a repository target with pattern of ./net/sf/ehcache/.*, this pattern matches all artifacts under path /net/sf/ehcache/. What if one project requires more than one groupId? Like Ehcache, it also needs net.sf.jsr107cache. It's ok, I can add more than one pattern for a repository target, in this case I also add "./net/sf/jsr107cache/.*". The name field in this figure is free form, it doesn't have to be a package name or a groupId, but I set the name to the main groupId to make it easier to find this target in the future.
Step 2: Create privileges
Once the repository target is created, we can create privileges based on it (along with a repository or group). Open the Privileges panel by clicking on Privileges under in the Security section of the Nexus application menu. Once you see the Privileges panel, click the Add button, select Repository Target Privilege. You need to fill in the name, description, repository, and repository target of the privilege. Here I choose repository target net.sf.ehcache and I target the repository Release (Repo). You can also choose "All Repositories" if you want to define a global privilege. I usually set the name and description to match the name of the groupId and which repositories the target applies to.
Click Save, then your CRUD privileges are created on repository Release, based on repository target net.sf.ehcache. You should see the following four privileges after clicking on Save.
Step 3: Create a Sonatype Nexus Repository role (or a user)
The next step is to create a user for the open source project that needs to have these privileges. In the case of ehcache, we define an ehcache administrative user, and we assign the privileges we just created to this new user.
Alternatively, we could create a new Nexus Role which contains these four new privileges and we could assign this role to users that need to have access to the ehcache repository target. I can assign these privileges to the Ehcache Admin role (it's easy to create a role in Sonatype Nexus Repository, just click on Roles under Security in the menu). Users who are assigned this new role role can then deploy artifacts to /net/sf/ehcache/ or /net/sf/jsr107cache/ of repository Release, but they can not deploy artifacts to other paths of this repository.
Conclusion
Following this pattern, we can create privileges for Plexus artifacts, for Sonatype artifacts,and for any other project as long as we know the groupId. I've found that this approach preferable to the approach that used hundreds of independent Maven repositories. We now have a single repository with multiple, project-specific privilege sets, and the process of adding new roles and privileges is very straightforward. We've made it past 100, now we're ready for 1000.
Written by Juven Xu
Juven is a former Software Engineer at Sonatype. He is now a Staff Engineer & Team Leader at Alibaba Group.