Pypi Repo for airgap env

Let’s take as an example py dependencies for Netbox

 1# Tools needed
 2dnf install -y python3.11
 3pip install --upgrade pip setuptool python-pypi-mirror twine
 4
 5# init mirror
 6python3.11 -m venv mirror
 7mkdir download
 8
 9# Get list of Py packages needed
10curl raw.githubusercontent.com/netbox-community/netbox/v3.7.3/requirements.txt -o requirements.txt
11echo pip >> requirements.txt
12echo setuptools >> requirements.txt
13echo uwsgi >> requirements.txt
14
15# Make sure repository CA is installed
16curl http://pki.server/pki/cacerts/ISSUING_CA.pem -o /etc/pki/ca-trust/source/anchors/issuing.crt
17curl http://pki.server/pki/cacerts/ROOT_CA.pem -o /etc/pki/ca-trust/source/anchors/root.crt
18update-ca-trust
19
20
21source mirror/bin/activate
22pypi-mirror download -b -d download -r requirements.tx
23twine upload  --repository-url https://nexus3.server/repository/internal-pypi/ download/*.whl --cert /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
24twine upload  --repository-url https://nexus3.server/repository/internal-pypi/ /download/*.tar.gz --cert /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem

Then on target host inside /etc/pip.conf :

1[global]
2index=https://nexus3.server/repository/internal-pypi/
3index-url=https://nexus3.server/repository/internal-pypi/simple
4trusted-host=nexus3.server

Bonus point

How to finish this Netbox installation :

 1# install roles and collections dependencies
 2ansible-galaxy install geerlingguy.postgresql davidwittman.redis
 3ansible-galaxy collection install community.postgresql
 4
 5# latest release is not yet available on ansible galaxy, but is required for newest versions of netbox
 6curl -L -o ansible-role-netbox.tar.gz https://github.com/lae/ansible-role-netbox/archive/refs/tags/v1.0.6.tar.gz
 7ansible-galaxy collection install ansible-role-netbox.tar.gz
 8
 9#Download tar packages for redis and netbox, then store them next to the playbook
10curl -L https://github.com/redis/redis/archive/refs/tags/7.2.4.tar.gz -O
11curl -L https://github.com/netbox-community/netbox/archive/refs/tags/v3.7.3.tar.gz -O
  • prepare netbox-vars.yml :
 1var_hostname: cmdb01-server
 2var_domain: example.com
 3postgresql_version: "15"
 4netbox_python_packages:
 5  - python3.11
 6  - python3.11-devel
 7  - python3.11-setuptools
 8  - python3.11-psycopg2
 9  - python3.11-pip
10netbox_python_binary: /usr/bin/python3.11
11netbox_cert: "{{ lookup('hashi_vault', 'secret=kv/data/mgt/cmdb:ssl_cert') }}"
12netbox_key: "{{ lookup('hashi_vault', 'secret=kv/data/mgt/cmdb:ssl_key') }}"
13redis_bind: 127.0.0.1
14redis_version: "7.2.4"
15redis_tarball: "redis-{{ redis_version }}.tar.gz"
16netbox_stable: true
17netbox_database_socket: "{{ postgresql_unix_socket_directories[0] }}"
18netbox_superuser_password: "{{ lookup('hashi_vault', 'secret=kv/data/mgt/cmdb:admin_password') }}"
19netbox_socket: "127.0.0.1:8000"
20netbox_protocol: uwsgi
21netbox_git: false
22netbox_install_epel: false
23netbox_stable_version: "3.7.3"
24netbox_stable_uri: "/tmp/netbox-{{ netbox_stable_version }}.tar.gz"
25netbox_config:
26  ALLOWED_HOSTS:
27    - {{ var_hostname }}.{{ var_domain }}
28    - {{ var_hostname }}
29    - netbox.{{ var_domain }}
30    - netbox
31  MEDIA_ROOT: "{{ netbox_shared_path }}/media"
32  REPORTS_ROOT: "{{ netbox_shared_path }}/reports"
33  SCRIPTS_ROOT: "{{ netbox_shared_path }}/scripts"
34postgresql_users:
35  - name: "{{ netbox_database_user }}"
36    role_attr_flags: CREATEDB,NOSUPERUSER
  • prepare playbooks
  1---
  2- name: install netbox
  3  hosts: "{{ var_hostname }}"
  4  become: yes
  5  roles:
  6    - geerlingguy.postgresql
  7    - davidwittman.redis
  8    - ansible-role-netbox
  9
 10  pre_tasks:
 11    - name: Copy netbox source
 12      copy:
 13        src: "netbox-{{ netbox_stable_version }}.tar.gz"
 14        dest: "{{ netbox_stable_uri }}"
 15    - name: Set postgresql module stream
 16      copy:
 17        content: |
 18          [postgresql]
 19          name=postgresql
 20          stream={{ postgresql_version }}
 21          profiles=
 22          state=enabled          
 23        dest: /etc/dnf/modules.d/postgresql.module
 24        owner: root
 25        group: root
 26        mode: 0644
 27        
 28  post_tasks:
 29    - name: Install nginx
 30      dnf:
 31        name: nginx
 32        state: latest
 33 
 34    - name: Ensure dirs exist
 35      file:
 36        path: "{{ item }}"
 37        state: directory
 38      loop:
 39        - /usr/share/ssl/certs
 40        - /usr/share/ssl/private
 41 
 42    - name: Deploy netbox SSL cert and key
 43      copy:
 44        content: "{{ item.src | b64decode }}"
 45        dest: "{{ item.dest }}"
 46      loop:
 47        - src: "{{ netbox_cert }}"
 48          dest: /usr/share/ssl/certs/netbox.crt
 49        - src: "{{ netbox_key }}"
 50          dest: /usr/share/ssl/private/netbox.key
 51 
 52    - name: Deploy nginx config
 53      copy:
 54        content: |
 55          server {
 56              listen       80;
 57              server_name  {{ var_hostname }},netbox;
 58              rewrite ^ https://$http_host$request_uri? permanent;    # force redirect http to https
 59          }
 60          server {
 61              listen          443 ssl;
 62              server_name     {{ var_hostname }},netbox;          
 63 
 64              access_log      /var/log/nginx/access_ssl.log combined;
 65              error_log       /var/log/nginx/error_ssl.log error;
 66 
 67              client_max_body_size 25m;
 68              keepalive_timeout 5;
 69 
 70              #SSL Settings
 71              ssl on;
 72              ssl_certificate /usr/share/ssl/certs/netbox.crt;
 73              ssl_certificate_key /usr/share/ssl/private/netbox.key;
 74 
 75              location /static/ {
 76                  alias /srv/netbox/current/netbox/static/;
 77              }
 78 
 79              location / {
 80                  uwsgi_pass 127.0.0.1:8000;
 81                  include uwsgi_params;
 82                  proxy_set_header X-Forwarded-Host $http_host;
 83                  proxy_set_header X-Real-IP $remote_addr;
 84                  proxy_set_header X-Forwarded-Proto $scheme;
 85              }
 86 
 87          }
 88        dest: /etc/nginx/conf.d/netbox.conf
 89 
 90    - name: Allow proxy connection
 91      seboolean:
 92        name: httpd_can_network_connect
 93        persistent: true
 94        state: true
 95      tags:
 96        - selinux
 97 
 98    - name: Set context for static dir
 99      sefcontext:
100        target: "{{ netbox_home }}/current/netbox/static(/.*)?"
101        setype: httpd_sys_content_t
102        state: present
103      tags:
104        - selinux
105 
106    - name: Apply context
107      command: restorecon -irv {{ netbox_home }}/current/netbox/static
108      register: restorecon
109      changed_when: restorecon.stdout | length > 0
110      tags:
111        - selinux
112 
113    - name: Start nginx
114      service:
115        name: nginx
116        state: started
117        enabled: true
118 
119    - name: Allow https
120      firewalld:
121        service: https
122        permanenet: true
123        state: enabled
  • Execute playbook ansible-playbook netbox.yml -e "@netbox-vars.yml"