diff --git a/.github/workflows/molecule_tests.yml b/.github/workflows/molecule_tests.yml index a7ea29157d..abb151d691 100644 --- a/.github/workflows/molecule_tests.yml +++ b/.github/workflows/molecule_tests.yml @@ -38,6 +38,7 @@ jobs: - freetds # - friends_of_pul - geaccirc + - gitlab # - geoserver - hr_share - imagemagick diff --git a/group_vars/gitlab/production.yml b/group_vars/gitlab/production.yml new file mode 100644 index 0000000000..803f8ddb8b --- /dev/null +++ b/group_vars/gitlab/production.yml @@ -0,0 +1,5 @@ +--- +gitlab_pu_ldap_bind_dn: "{{ vault_gitlab_pu_ldap_bind_dn }}" +gitlab_pu_ldap_password: "{{ vault_gitlab_ldap_password }}" +gitlab_loadbalancer_domain_name: "gitlab.lib.princeton.edu" +gitlab_trusted_proxies: "'128.112.203.144', '128.112.203.145', '128.112.203.146'" diff --git a/group_vars/gitlab/staging.yml b/group_vars/gitlab/staging.yml new file mode 100644 index 0000000000..2368bc3401 --- /dev/null +++ b/group_vars/gitlab/staging.yml @@ -0,0 +1,5 @@ +--- +gitlab_pu_ldap_bind_dn: "{{ vault_gitlab_pu_ldap_bind_dn }}" +gitlab_pu_ldap_password: "{{ vault_gitlab_ldap_password }}" +gitlab_loadbalancer_domain_name: "gitlab-staging.lib.princeton.edu" +gitlab_trusted_proxies: "'172.20.80.13', '172.20.80.14', '172.20.80.19'" diff --git a/group_vars/gitlab/vault.yml b/group_vars/gitlab/vault.yml new file mode 100644 index 0000000000..02715e88d1 --- /dev/null +++ b/group_vars/gitlab/vault.yml @@ -0,0 +1,18 @@ +$ANSIBLE_VAULT;1.1;AES256 +62616336613866616662323462653233383466376136663336316130383334396339373263616430 +6363643366336264643163366434373964323534363538300a303562326564663039656434643437 +65333435306338323461366431363131666236393738333930623139643333616431643031653432 +3661373165373964370a663261653065363362626538373731653965346365363030396666363664 +63613134373962663930366637616565623938306166653339303664656531626533313366336634 +36623262353234356564353139316231316539393766643166376432613635343263343165636237 +31636631376431393531323934363633363261643539333533613535396135653434613935626435 +37323162666265623562663730343435643966356664313263623735303432633963373663323563 +31633535633336613738386134626233616364343063316235356263333534336262666364343336 +34646334616639346138396134386538356334313066336362663466313266303131313263643630 +64353532393833383361663761633438383630326665663339663239333537323130303830393630 +61306561663432343437643138363836373335313963656636326365326262373633316635346539 +37383263376366633438373365333337623834643534353139643630396463306531353034316662 +31353230316239306534373063363933616433643833663465306563313661626562613138396139 +31303432393963353436633431366262373465383632333764356135643230646133383932396637 +37383562633234356336333766636234343265363161633031393265346165356465343838626432 +37646534316536653463386134636264653639633334346430396462343636316438 diff --git a/inventory/all_projects/gitlab b/inventory/all_projects/gitlab new file mode 100644 index 0000000000..b4c132341f --- /dev/null +++ b/inventory/all_projects/gitlab @@ -0,0 +1,4 @@ +[gitlab_production] +gitlab-prod-vm.lib.princeton.edu +[gitlab_staging] +gitlab-staging-vm.lib.princeton.edu diff --git a/inventory/by_environment/production b/inventory/by_environment/production index 1adde4148d..35f5ce5cd2 100644 --- a/inventory/by_environment/production +++ b/inventory/by_environment/production @@ -21,6 +21,7 @@ figgy_production friends_of_pul_production geaccirc_production geniza_production +gitlab_production lae_production lib_jobs_production libsftp_production diff --git a/inventory/by_environment/staging b/inventory/by_environment/staging index 3195cbcbb4..2950d2d88a 100644 --- a/inventory/by_environment/staging +++ b/inventory/by_environment/staging @@ -20,6 +20,7 @@ figgy_staging friends_of_pul_staging geaccirc_staging geniza_staging +gitlab_staging lae_staging lib_jobs_staging libsftp_staging diff --git a/playbooks/Gitlab.yml b/playbooks/Gitlab.yml new file mode 100644 index 0000000000..809abdc292 --- /dev/null +++ b/playbooks/Gitlab.yml @@ -0,0 +1,20 @@ +--- +# by default this playbook runs in the staging environment +# to run in production, pass '-e runtime_env=production' + +- name: build our in-house GitLab instances + hosts: gitlab_{{ runtime_env | default('staging') }} + remote_user: pulsys + become: true + vars_files: + - ../group_vars/gitlab/{{ runtime_env | default('staging') }}.yml + - ../group_vars/gitlab/vault.yml + roles: + - role: gitlab + + post_tasks: + - name: tell everyone on slack you ran an ansible playbook + community.general.slack: + token: "{{ vault_pul_slack_token }}" + msg: "Ansible ran `{{ ansible_play_name }}` on {{ inventory_hostname }}" + channel: "{{ slack_alerts_channel }}" diff --git a/roles/example/molecule/default/converge.yml b/roles/example/molecule/default/converge.yml index 9b84c613c4..470bb54fdf 100644 --- a/roles/example/molecule/default/converge.yml +++ b/roles/example/molecule/default/converge.yml @@ -5,11 +5,11 @@ - running_on_server: false become: true pre_tasks: - - name: update cache - apt: + - name: Update cache + ansible.builtin.apt: update_cache: true cache_valid_time: 600 tasks: - name: "Include example" - include_role: + ansible.builtin.include_role: name: example diff --git a/roles/example/molecule/default/molecule.yml b/roles/example/molecule/default/molecule.yml index 0e1659c89a..fc1de4aea1 100644 --- a/roles/example/molecule/default/molecule.yml +++ b/roles/example/molecule/default/molecule.yml @@ -9,8 +9,8 @@ lint: | ansible-lint platforms: - name: instance - image: "quay.io/pulibrary/jammy-ansible:latest" - command: "" + image: "ghcr.io/pulibrary/pul_containers:jammy_multi" + command: "sleep infinity" volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro privileged: true diff --git a/roles/example/molecule/default/verify.yml b/roles/example/molecule/default/verify.yml index d2d3aea12a..6972c17318 100644 --- a/roles/example/molecule/default/verify.yml +++ b/roles/example/molecule/default/verify.yml @@ -3,18 +3,18 @@ hosts: all gather_facts: false tasks: - - name: check ruby package status - package: - name: "{{ item }}" - state: present - check_mode: true - register: pkg_status - loop: - - ruby-switch - - ruby2.6-dev - - ruby2.6 + - name: Check ruby package status + ansible.builtin.package: + name: "{{ item }}" + state: present + check_mode: true + register: pkg_status + loop: + - ruby-switch + - ruby2.6-dev + - ruby2.6 - - name: test for ruby packages - assert: - that: - - not pkg_status.changed + - name: Test for ruby packages + ansible.builtin.assert: + that: + - not pkg_status.changed diff --git a/roles/gitlab/README.md b/roles/gitlab/README.md new file mode 100644 index 0000000000..10600a15f2 --- /dev/null +++ b/roles/gitlab/README.md @@ -0,0 +1,21 @@ +Role Name +========= + +Installs and configures [Gitlab CE](https://about.gitlab.com/install/#ubuntu) +Requirements +------------ + + +Role Variables +-------------- + +```bash +gitlab_trusted_proxies: "'172.20.80.13', '172.20.80.14', '172.20.80.19'" +gitlab_loadbalancer_domain_name: "git-env.lib.princeton.edu" +``` + + +BSD + + +An optional section for the role authors to include contact information, or a website (HTML is not allowed). diff --git a/roles/gitlab/defaults/main.yml b/roles/gitlab/defaults/main.yml new file mode 100644 index 0000000000..36c9afed80 --- /dev/null +++ b/roles/gitlab/defaults/main.yml @@ -0,0 +1,7 @@ +--- +# defaults file for roles/gitlab +gitlab_pu_ldap_bind_dn: "bind_name" +gitlab_pu_ldap_password: "ldap_password" +gitlab_loadbalancer_domain_name: "example.edu" +gitlab_loadbalancer_real_ip_trusted: "{{ gitlab_trusted_proxies }}" +gitlab_trusted_proxies: "'192.168.0.0', '10.0.0.0', '172.16.0.0'" diff --git a/roles/gitlab/handlers/main.yml b/roles/gitlab/handlers/main.yml new file mode 100644 index 0000000000..95a09eb11a --- /dev/null +++ b/roles/gitlab/handlers/main.yml @@ -0,0 +1,11 @@ +--- +# handlers file for roles/gitlab +- name: Restart mail service + ansible.builtin.service: + name: postfix + state: restarted + +- name: Reconfigure gitlab + ansible.builtin.command: gitlab-ctl reconfigure + changed_when: false + when: running_on_server diff --git a/roles/gitlab/meta/main.yml b/roles/gitlab/meta/main.yml new file mode 100644 index 0000000000..26ba14f92e --- /dev/null +++ b/roles/gitlab/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + role_name: gitlab + company: Princeton University Library + description: Install Gitlab CE + author: pulibrary + + license: MIT + + min_ansible_version: "2.9" + + platforms: + - name: Ubuntu + versions: + - jammy +dependencies: [] diff --git a/roles/gitlab/molecule/default/converge.yml b/roles/gitlab/molecule/default/converge.yml new file mode 100644 index 0000000000..aa79570d3b --- /dev/null +++ b/roles/gitlab/molecule/default/converge.yml @@ -0,0 +1,15 @@ +--- +- name: Converge + hosts: all + vars: + - running_on_server: false + become: true + pre_tasks: + - name: Update cache + ansible.builtin.apt: + update_cache: true + cache_valid_time: 600 + tasks: + - name: "Include gitlab" + ansible.builtin.include_role: + name: gitlab diff --git a/roles/gitlab/molecule/default/molecule.yml b/roles/gitlab/molecule/default/molecule.yml new file mode 100644 index 0000000000..fc1de4aea1 --- /dev/null +++ b/roles/gitlab/molecule/default/molecule.yml @@ -0,0 +1,22 @@ +--- +scenario: + name: default +driver: + name: docker +lint: | + set -e + yamllint . + ansible-lint +platforms: + - name: instance + image: "ghcr.io/pulibrary/pul_containers:jammy_multi" + command: "sleep infinity" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + pre_build_image: true +provisioner: + name: ansible + log: true +verifier: + name: ansible diff --git a/roles/gitlab/molecule/default/verify.yml b/roles/gitlab/molecule/default/verify.yml new file mode 100644 index 0000000000..15ed19a6f2 --- /dev/null +++ b/roles/gitlab/molecule/default/verify.yml @@ -0,0 +1,18 @@ +--- +- name: Verify + hosts: all + gather_facts: false + tasks: + - name: Check gitlab-ce status + ansible.builtin.package: + name: "{{ item }}" + state: present + check_mode: true + register: pkg_status + loop: + - gitlab-ce + + - name: test for gitlab-ce packages + ansible.builtin.assert: + that: + - not pkg_status.changed diff --git a/roles/gitlab/tasks/main.yml b/roles/gitlab/tasks/main.yml new file mode 100644 index 0000000000..8099e03c7e --- /dev/null +++ b/roles/gitlab/tasks/main.yml @@ -0,0 +1,67 @@ +--- +# tasks file for roles/gitlab +- name: Gitlab | Install required packages + ansible.builtin.apt: + name: + - curl + - ca-certificates + - tzdata + - perl + - certbot + state: present + update_cache: true + +- name: Gitlab | Configure Postfix + # Example with debconf: + ansible.builtin.debconf: + name: postfix + question: postfix/{{ item.question }} + value: "{{ item.value }}" + vtype: "{{ item.vtype }}" + notify: Restart mail service + loop: + # General mail configuration type + - question: main_mailer_type + value: "Satellite system" + vtype: select + # SMTP relay host + - question: relayhost + value: "lib-ponyexpr-prod.princeton.edu" + vtype: string + +- name: Gitlab | Install required postfix + ansible.builtin.apt: + name: postfix + autoremove: true + state: present + environment: + DEBIAN_FRONTEND: noninteractive + +- name: Gitlab | update acme certificates for {{ inventory_hostname }} + ansible.builtin.command: /usr/bin/certbot certonly --standalone --non-interactive --agree-tos --email lsupport@princeton.edu --server https://acme.sectigo.com/v2/InCommonRSAOV --eab-kid {{ vault_acme_eab_kid }} --eab-hmac-key {{ vault_acme_eab_hmac_key }} --domain {{ inventory_hostname }} --cert-name {{ inventory_hostname }} + changed_when: false + when: running_on_server + +- name: GitLab | Add package repository (alternative) + ansible.builtin.get_url: + url: https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh + dest: /tmp/script.deb.sh + mode: "0755" + +- name: GitLab | Execute the script + ansible.builtin.command: /tmp/script.deb.sh + changed_when: false + +- name: GitLab | install CE package + ansible.builtin.apt: + name: gitlab-ce + state: present + +- name: Copy GitLab configuration file + ansible.builtin.template: + src: gitlab.rb.j2 + dest: /etc/gitlab/gitlab.rb + owner: root + group: root + mode: "0600" + notify: Reconfigure gitlab diff --git a/roles/gitlab/templates/gitlab.rb.j2 b/roles/gitlab/templates/gitlab.rb.j2 new file mode 100644 index 0000000000..a57d05227b --- /dev/null +++ b/roles/gitlab/templates/gitlab.rb.j2 @@ -0,0 +1,57 @@ +# {{ ansible_managed | comment }} +## GitLab configuration settings +##! https://gitlab.com/gitlab-org/omnibus-gitlab/blame/master/files/gitlab-config-template/gitlab.rb.template +##! /opt/gitlab/etc/gitlab.rb.template +##! You can run `gitlab-ctl diff-config` to compare the contents of the current gitlab.rb with +##! the gitlab.rb.template from the currently running version. +## GitLab URL +##! https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-the-external-url-for-gitlab +##! https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html +external_url 'https://{{ gitlab_loadbalancer_domain_name }}' + +################################################################################ +## gitlab.yml configuration +##! Docs: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/gitlab.yml.md +################################################################################ +gitlab_rails['gitlab_ssh_host'] = '{{ inventory_hostname }}' +gitlab_rails['smtp_enable'] = true +gitlab_rails['smtp_address'] = "localhost" +gitlab_rails['gitlab_email_enabled'] = true +gitlab_rails['gitlab_default_theme'] = 2 +gitlab_rails['trusted_proxies'] = [{{ gitlab_trusted_proxies }}] +gitlab_rails['lfs_enabled'] = true + gitlab_rails['lfs_storage_path'] = "/var/opt/gitlab/gitlab-rails/shared/lfs-objects" +gitlab_rails['ldap_enabled'] = true +gitlab_rails['ldap_servers'] = { + 'main' => { + 'label' => 'pu_LDAP', + 'host' => 'ldapproxy.princeton.edu', + 'port' => 636, + 'uid' => 'sAMAccountName', + 'bind_dn'=> '{{ gitlab_pu_ldap_bind_dn }}', + 'password' => '{{ gitlab_pu_ldap_password }}', + 'encryption'=> 'simple_tls', + 'verify_certificates' => true, + 'timeout' => 10, + 'active_directory' => true, + 'user_filter'=> '(&(objectCategory=Person)(sAMAccountName=*))', + 'base'=> 'dc=pu,dc=win,dc=princeton,dc=edu', + 'retry_empty_result_with_codes' => [80], + 'allow_username_or_email_login' => false, + 'block_auto_created_users' => false + } +} +registry_external_url 'https://{{ inventory_hostname }}' +nginx['ssl_certificate'] = "/etc/letsencrypt/live/{{ inventory_hostname }}/fullchain.pem" +nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/{{ inventory_hostname }}/privkey.pem" +nginx['ssl_protocols'] = "TLSv1.2 TLSv1.3" +nginx['ssl_session_cache'] = "shared:SSL:10m" +nginx['ssl_session_tickets'] = "off" +nginx['listen_port'] = 443 +nginx['listen_https'] = true +nginx['real_ip_trusted_addresses'] = [{{ gitlab_loadbalancer_real_ip_trusted }}] +nginx['real_ip_header'] = 'X-Forwarded-For' +registry_nginx['enable'] = true +registry_nginx['listen_port'] = 5050 +registry_nginx['ssl_certificate'] = "/etc/letsencrypt/live/{{ inventory_hostname }}/fullchain.pem" +registry_nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/{{ inventory_hostname }}/privkey.pem" diff --git a/roles/gitlab/tests/inventory b/roles/gitlab/tests/inventory new file mode 100644 index 0000000000..878877b077 --- /dev/null +++ b/roles/gitlab/tests/inventory @@ -0,0 +1,2 @@ +localhost + diff --git a/roles/gitlab/tests/test.yml b/roles/gitlab/tests/test.yml new file mode 100644 index 0000000000..16c161d548 --- /dev/null +++ b/roles/gitlab/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - roles/gitlab diff --git a/roles/gitlab/vars/main.yml b/roles/gitlab/vars/main.yml new file mode 100644 index 0000000000..5897082261 --- /dev/null +++ b/roles/gitlab/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for roles/gitlab diff --git a/roles/nginxplus/files/conf/http/dev/gitlab_staging.conf b/roles/nginxplus/files/conf/http/dev/gitlab_staging.conf new file mode 100644 index 0000000000..a6378ae891 --- /dev/null +++ b/roles/nginxplus/files/conf/http/dev/gitlab_staging.conf @@ -0,0 +1,42 @@ +# Ansible managed +proxy_cache_path /var/cache/nginx/gitlab-staging/ keys_zone=gitlabstagingcache:10m; + +upstream gitlab-staging { + zone gitlab-staging 64k; + server gitlab-staging-vm.lib.princeton.edu:443 resolve; + sticky learn + create=$upstream_cookie_gitlabstagingcookie + lookup=$cookie_gitlabstagingcookie + zone=gitlabstagingclient_sessions:1m; +} + +server { + listen 80; + server_name gitlab-staging.lib.princeton.edu; + + location / { + return 301 https://$server_name$request_uri; + } +} + +server { + listen 443 ssl; + http2 on; + server_name gitlab-staging.lib.princeton.edu; + + ssl_certificate /etc/letsencrypt/live/gitlab-staging.lib/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/gitlab-staging.lib/privkey.pem; + ssl_session_cache shared:SSL:1m; + ssl_prefer_server_ciphers on; + + location / { + proxy_pass https://gitlab-staging; + proxy_cache gitlabstagingcache; + proxy_set_header Connection $http_connection; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} diff --git a/roles/nginxplus/files/conf/http/gitlab_prod.conf b/roles/nginxplus/files/conf/http/gitlab_prod.conf new file mode 100644 index 0000000000..2ffbd5e905 --- /dev/null +++ b/roles/nginxplus/files/conf/http/gitlab_prod.conf @@ -0,0 +1,42 @@ +# Ansible managed +proxy_cache_path /data/nginx/gitlab/NGINX_cache/ keys_zone=gitlabcache:10m; + +upstream gitlab { + zone gitlab 64k; + server gitlab-prod-vm.lib.princeton.edu:443 resolve; + sticky learn + create=$upstream_cookie_gitlabcookie + lookup=$cookie_gitlabcookie + zone=gitlabclient_sessions:1m; +} + +server { + listen 80; + server_name gitlab.lib.princeton.edu; + + location / { + return 301 https://$server_name$request_uri; + } +} + +server { + listen 443 ssl; + http2 on; + server_name gitlab.lib.princeton.edu; + + ssl_certificate /etc/letsencrypt/live/gitlab.lib/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/gitlab.lib/privkey.pem; + ssl_session_cache shared:SSL:1m; + ssl_prefer_server_ciphers on; + + location / { + proxy_pass https://gitlab; + proxy_cache gitlabcache; + proxy_set_header Connection $http_connection; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +}