Organizing a Restricted Software Package Repository on Linux

WILD

Administrator
Staff member
ADMIN
SELLER
SUPREME
MEMBER
Joined
Jan 21, 2025
Messages
219
Reaction score
632
Deposit
0$
In this article, I'd like to discuss how to organize a software package repository with limited access, using practical examples. Such a repository can be useful in various situations:If you have a test repository and its users are located far away, internet access to the repository is necessary, but it should not be accessible to just anyone.A developer may distribute a closed product that should only be accessible to authorized users. However, the full list of users is unknown in advance, and a quick way to provide access is needed.This could be a commercial repository with a paid subscription.And so on.What are the options for organizing such a repository? Let's consider several ideas.The first option is to create a VPN connection and distribute software settings to clients. However, this method requires users to perform a lot of steps to access the website with the packages, including installing and configuring the software.The second option is to use ready-made solutions, such as Spacewalk or Katello+Pulp, etc. These systems provide authorized access to the software. However, they are cumbersome, and much of the functionality may be redundant.The third option is to develop your own software for user validation and access. However, this requires not only setting up the client-side connection but also maintaining the server side. Furthermore, it requires ensuring compatibility with different operating system versions as they are updated. This is quite labor-intensive.The fourth option is to restrict access using a web server that restricts access to the repository website. For example, HTTP authentication can be used. It's quite common to see repository access restricted in this way; for example, a line like this in the repository settings requires authorization for access: baseurl=http://user:[email protected]/myrepo/dev-repo.An example flowchart of such a repository:
The advantage of this approach is that the client only needs to create one correct add-on file, and the system will function correctly. Most operating system package managers support this type of connection to the repository. User access can also be managed, granting and revoking it.However, there are also disadvantages. For example, if access should be temporary and automatically expire after a certain period of time, you must remember to reset the password for that user at the appropriate time. This requires additional software for access control.Another method for gaining access is using an SSL certificate.The scheme is identical to the previous one, but instead of a password database, a certificate database is used, and instead of a username:password combination, a user certificate is used.This scheme is also supported by many package managers; you simply specify the path to the received certificates. Most importantly, using a certificate, you can set the certificate's validity period, automatically solving the problem of temporary access. A very elegant solution.A similar solution is also used in the previously mentioned Spacewalk and Katello+Pulp.To implement this mechanism, you need to have a repository itself, with a prepared structure and located in the root of the server site, as well as a certificate database.The diagram below shows how this works:
Now for the practical part: we'll set up certificate access for a private package repository using cecemaut in command line mode:mkdir -p center && cd centergit clone https://github.com/bayrepo/cecemaut.git && cd cecemautExplain withNow let's create a configuration file in the utils/custom_config.sh directory with the following example contents:ROOT_DIR="/opt/certbase" #full path to the future certificate store, preferably an empty directoryCOUNTRY_NAME="RU" #two-letter country codeORG_NAME="MyOrgName" #organization nameCOMM_NAME="IP Testoviy" #additional organization nameSERT_PASS=$(cat ~/.pass) #password for the root and intermediate certificatesVAL_DAYS="3652" # number of days the root certificate is valid, for example, 10 yearsExplain withNow you need to run the certificate database preparation script:pushd utils && bash prepare.sh && popdExplain withThe root certificate and additional files will be created, and the entire database will be placed in the /opt/certbase/ca directory specified in the configuration.Next, the last step is to issue a certificate for the web server, in my case, nginx. Let's assume, for example, that the repository is located on the server at example1.com, which is the nginx virtual host.Let's request a 2-year certificate for it:pushd utils && bash make_server_cert.sh -t 731 example1.com && popdExplain withThe utility output shows the following lines (the output may change as cecemaut is updated):...Generated key set for server Installation:- [OUTPUTDATA] Private key: `/opt/certbase/ca/intermediate/private/example1.com.key.pem`;- [OUTPUTDATA_CERT] Server certificate: `/opt/certbase/ca/intermediate/certs/example1.com.cert.pem.5`;- [OUTPUTDATA] CA chain: `/opt/certbase/ca/intermediate/certs/ca-chain.cert.pem`;- [OUTPUTDATA] Revoked certificates list: `/opt/certbase/ca/intermediate/crl/ca-full.crl.pem`Explain withThese are the files that need to be included in nginx. This is what the configuration for the nginx host serving the repository would look like. For example, this would be the configuration file. /etc/nginx/conf.d/example1.com.conf:server { listen 8081 ssl; server_name example1.com www.example1.com; root /var/www/example1.com/html; index index.html; location/{ try_files $uri $uri/ =404; } access_log /var/log/nginx/example1.com.access.log; error_log /var/log/nginx/example1.com.error.log debug; ssl_certificate /opt/certbase/ca/intermediate/certs/example1.com.cert.pem.5; ssl_certificate_key /opt/certbase/ca/intermediate/private/example1.com.key.pem;ssl_client_certificate /opt/certbase/ca/intermediate/certs/ca-chain.cert.pem;ssl_crl /opt/certbase/ca/intermediate/crl/ca-full.crl.pem;ssl_verify_client on;keepalive_timeout 70;# other settings, if needed}Explain withFinally, let's issue a certificate for the client to access this server for a month:pushd utils && bash make_client_cert.sh -s example1.com -c user1@user1 -d 30 && popdExplain withThe utility outputs:...- [OUTPUTDATA] private key: `/opt/certbase/ca/client_certs/example1.com/private/user1@user1_private.key.pem`;- [OUTPUTDATA_CERT] server certificate: `/opt/certbase/ca/client_certs/example1.com/[email protected]`;- [OUTPUTDATA] CA chain: `/opt/certbase/ca/intermediate/certs/ca-chain.cert.pem`Explain withThese files need to be sent to the client.Now, from the client side, you can access the repository:We access it without a certificate (in this case, lynx was started with FORCE_SSL_PROMPT:YES, because in --dump mode it stops working, complaining about the self-signed certificate and requires the CA chain; with a full set of certificates, everything works fine):lynx --dump https://example1.com:8081400 Bad RequestNo required SSL certificate was sent__________________________________________________________________nginx/1.20.1Explain withNow with the certificate:SSL_CLIENT_CERT_FILE=/opt/certbase/ca/client_certs/example1.com/[email protected] SSL_CLIENT_KEY_FILE=/opt/certbase/ca/client_certs/example1.com/private/user1@user1_private.key.pem SSL_CERT_FILE=/opt/certbase/ca/intermediate/certs/ca-chain.cert.pem lynx --dump https://example1.com:8081Command output:List of packages available in the repositoryTotal 26 packages(BUTTON) Debug…Explain withNow everything works correctly.The next step is to enable the repository, for example, in dnf. To do this, create the file /etc/yum.repos.d/test.repo with the following contents:[test]name = testenabled = 1sslverify = 1gpgcheck = 1baseurl = https://example1.com:8081sslclientkey=/opt/certbase/ca/client_certs/example1.com/private/user1@user1_private.key.pemsslclientcert=/opt/certbase/ca/client_certs/example1.com/[email protected]=/opt/certbase/ca/intermediate/certs/ca-chain.cert.pemExplain withand check the packages in it:yum list --disablerepo="*"
 
Top Bottom