Compare commits

...

19 Commits

Author SHA1 Message Date
Yohann D'ANELLO 8c4684a450
[nginx] setup nginx
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-25 09:48:58 +02:00
Yohann D'ANELLO f9491c6553
[certbot] Configure certbot
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-25 08:26:01 +02:00
Yohann D'ANELLO c0a466db6a
Configure sudoers
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 21:01:22 +02:00
Yohann D'ANELLO 3fedc63db3
Mount home directories
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 20:51:07 +02:00
Yohann D'ANELLO 0a85cd22ff
Connexion au serveur LDAP
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 19:30:20 +02:00
Yohann D'ANELLO a8c4bf141b
Forget dt for now
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 19:22:17 +02:00
Yohann D'ANELLO 2232e7c213
[ntp_server] router is the NTP server
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 19:00:01 +02:00
Yohann D'ANELLO 6a3010816a
Update natural scroll for i3
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 18:49:03 +02:00
Yohann D'ANELLO e8661bbddb
Update slapd server
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 18:48:04 +02:00
Yohann D'ANELLO 571f694ed1
templier is here
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 18:28:25 +02:00
Yohann D'ANELLO 1115f7d0a8
NTP client/server, prepare slapd
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-29 15:12:28 +02:00
Yohann D'ANELLO 7f39ea724a
Read become password from pass
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 10:48:05 +02:00
Yohann D'ANELLO 475fe06fb7
[apt] Better configuration to pin packages
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 10:43:05 +02:00
Yohann D'ANELLO 1d1b31c461
Remove some bash aliases on servers
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 10:34:52 +02:00
Yohann D'ANELLO 8d649970ee
Fix common tools
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 10:24:34 +02:00
Yohann D'ANELLO 3ab93fd509
[apt] Update cache
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 00:46:07 +02:00
Yohann D'ANELLO 680b09ca2c
Move playbooks in a separate directory
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 00:41:19 +02:00
Yohann D'ANELLO 4814d7d6ae
[apt] Pin some packages from other versions
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 00:32:27 +02:00
Yohann D'ANELLO 7388125008
[apt] Configure APT sources
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-07 23:55:10 +02:00
78 changed files with 1752 additions and 132 deletions

View File

@ -1,11 +1,15 @@
[defaults]
# Explicitely redefined some defaults to make play execution work
roles_path = ./roles
vars_plugins = ./vars_plugins
inventory = ./hosts
timeout = 60
# ask_vault_pass = True
[privilege_escalation]
become = True
become_ask_pass = True
# Use a separate module to read passwords from pass
become_ask_pass = False
[ssh_connection]
pipelining = True

View File

@ -17,6 +17,10 @@ ansible_header: |
+++++++++++++++++++++++++++++++++++++++++++++++++++
glob_ldap:
servers:
- 172.16.42.1
base: 'dc=ynerant,dc=fr'
pass:

4
group_vars/all/home.yml Normal file
View File

@ -0,0 +1,4 @@
---
glob_home:
ip: 172.16.42.1
mountpoint: /rpool/home

3
group_vars/all/ntp.yml Normal file
View File

@ -0,0 +1,3 @@
glob_ntp_client:
servers:
- ntp.adm.ynerant.fr

8
group_vars/certbot.yml Normal file
View File

@ -0,0 +1,8 @@
---
glob_certbot:
- dns_rfc2136_server: '172.16.42.103'
dns_rfc2136_name: certbot_challenge.
dns_rfc2136_secret: "{{ vault.certbot_dns_secret }}"
mail: ynerant@crans.org
certname: ynerant.fr
domains: "*.ynerant.fr"

7
group_vars/debian.yml Normal file
View File

@ -0,0 +1,7 @@
---
glob_apt:
mirror: "http://mirror.adm.ynerant.fr/"
backports: false
extra_repositories: []
pin:
bullseye: []

32
group_vars/nginx.yml Normal file
View File

@ -0,0 +1,32 @@
---
glob_nginx:
contact: ynerant@crans.org
who: "Ÿnérant"
service_name: service
ssl:
# Add adm.ynerant.fr if necessary
- name: ynerant.fr
cert: /etc/letsencrypt/live/ynerant.fr/fullchain.pem
cert_key: /etc/letsencrypt/live/ynerant.fr/privkey.pem
trusted_cert: /etc/letsencrypt/live/ynerant.fr/chain.pem
servers:
- ssl: false # Replace by crans.org or adm.crans.org
default: true
server_name:
- "default"
- "_"
root: "/var/www/html"
locations:
- filter: "/"
params: []
additional_params: []
upstreams: []
auth_passwd: []
default_server:
default_ssl_server:
default_ssl_domain: ynerant.fr
real_ip_from:
- "172.16.0.0/16"
- "fd00:0:0:42::/64"
deploy_robots_file: false

View File

@ -0,0 +1,46 @@
loc_certbot:
- dns_rfc2136_server: '172.16.42.103'
dns_rfc2136_name: certbot_challenge.
dns_rfc2136_secret: "{{ vault.certbot_dns_secret }}"
mail: ynerant@crans.org
certname: ynerant.fr
domains: "ynerant.fr, *.ynerant.fr, ens.kitchen, *.ens.kitchen, ananas.paris, *.ananas.paris, saperlistpopette.fr, *.saperlistpopette.fr"
loc_nginx:
servers: []
ssl:
- name: ynerant.fr
cert: /etc/letsencrypt/live/ynerant.fr/fullchain.pem
cert_key: /etc/letsencrypt/live/ynerant.fr/privkey.pem
trusted_cert: /etc/letsencrypt/live/ynerant.fr/chain.pem
glob_reverseproxy:
redirect_dnames: []
reverseproxy_sites:
- {from: mailu.ynerant.fr, to: 172.16.42.104}
# - {from: mirror.adm.ynerant.fr, to: "https://ftps.crans.org"}
- {from: element.ynerant.fr, to: "172.16.42.199:8002"}
- {from: hydrogen.ynerant.fr, to: "172.16.42.199:8003"}
- {from: git.ynerant.fr, to: "172.16.42.199:8007"}
- {from: cloud.ynerant.fr, to: "172.16.42.199:8007"}
# - {from: notls.adh.crans.org, to: "172.16.42.199:8011"}
- {from: thelounge.ynerant.fr, to: "172.16.42.199:8012"}
- {from: bibliogram.ynerant.fr, to: "172.16.42.199:8014"}
- {from: reddit.ynerant.fr, to: "172.16.42.199:8015"}
- {from: teddit.ynerant.fr, to: "172.16.42.199:8015"}
- {from: whoami.ynerant.fr, to: "172.16.42.199:8016"}
- {from: saperlistpopette.fr, to: "172.16.42.199:8010"}
- {from: kfet.saperlistpopette.fr, to: "172.16.42.199:8010"}
- {from: ens.kitchen, to: "https://perso.crans.org/club-kitchens/"}
redirect_sites: []
# - {from: machin.ynerant.fr, to: truc.ynerant.fr}
static_sites:
- ynerant.fr
- thelounge.ynerant.fr

10
group_vars/slapd.yml Normal file
View File

@ -0,0 +1,10 @@
---
glob_slapd:
master_ip: "172.16.42.1"
ip: "172.16.42.1"
replica: false
# master_ip: "{{ query('ldap', 'ip', 'templier', 'adm') | ipv6 | first }}"
regex: "^(role:(dhcp|dns|dns-primary|dns-secondary|ftp|gitlab|miroir|ntp|pve|radius|backup)|ecdsa-sha2-nistp256:.*|ssh-(ed25519|dss|rsa):.*)$"
replication_credentials: "{{ vault.ldap_replication_credentials }}"
private_key: "{{ vault.ldap_private_key }}"
certificate: "{{ vault.ldap_certificate }}"

8
group_vars/virtu.yml Normal file
View File

@ -0,0 +1,8 @@
---
service_apt:
extra_repositories:
- name: pve-entreprise
repositories:
- url: "{{ glob_apt.mirror }}proxmox/debian/pve"
version: "{{ ansible_distribution_release }}"
tags: "pve-no-subscription"

44
hosts
View File

@ -1,16 +1,46 @@
[server]
templier.adh.crans.org
dt.adh.crans.org
[archlinux:children]
perso
[certbot]
proxy.adm.ynerant.fr
[debian:children]
server
[nginx:children]
reverseproxy
[ntp_server]
routeur-templier.adm.ynerant.fr
[perso]
ynerant-pc.fil.sand.auro.re
ynerant-thinkpad.wifi.sand.auro.re
localhost
[crans]
odlyd.crans.org
tealc.crans.org
zamok.crans.org
[reverseproxy]
proxy.adm.ynerant.fr
[server:children]
virtu
vm
[slapd]
templier.adm.ynerant.fr
[virtu]
# dt.adh.crans.org
templier.adm.ynerant.fr
[vm]
routeur-templier.adm.ynerant.fr
proxy.adm.ynerant.fr
dns.adm.ynerant.fr
mailu.adm.ynerant.fr
psql.adm.ynerant.fr
synapse.adm.ynerant.fr
docker.adm.ynerant.fr
# candilib.adm.ynerant.fr
[all:vars]
# Force remote to use Python 3

7
plays/apt.yml Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env ansible-playbook
---
- hosts: debian
vars:
apt: "{{ glob_apt | default({}) | combine(service_apt | default({})) | combine(loc_apt | default({})) }}"
roles:
- apt

View File

@ -1,24 +1,33 @@
#!/usr/bin/env ansible-playbook
---
- import_playbook: apt.yml
- import_playbook: ntp.yml
- import_playbook: ldap-client.yml
- import_playbook: home.yml
- hosts: debian
roles:
- sudo
- hosts: all
roles:
- cli-utils
- vim
- ssh
- hosts: templier.adh.crans.org
roles:
- bind
- docker
become: yes
#- hosts: templier.adh.crans.org
# roles:
# - bind
# - docker
# become: yes
- hosts: perso
roles:
- sudo
# - sudo
- systemd
- pacman
- ntp
- ntp-client-arch
- texlive
- xorg
- i3

7
plays/certbot.yml Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env ansible-playbook
---
- hosts: certbot
vars:
certbot: "{{ glob_certbot | default(service_certbot | default(loc_certbot | default([]))) }}"
roles:
- certbot

7
plays/home.yml Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env ansible-playbook
---
- hosts: debian
vars:
home: '{{ glob_home | combine(loc_home | default({})) }}'
roles:
- home

7
plays/ldap-client.yml Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env ansible-playbook
---
- hosts: debian
vars:
ldap: '{{ glob_ldap | combine(loc_ldap | default({})) }}'
roles:
- ldap-client

14
plays/nginx.yml Executable file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env ansible-playbook
---
- hosts: nginx,!reverseproxy
vars:
nginx: "{{ glob_nginx | default({}) | combine(service_nginx | default({})) | combine(loc_nginx | default({})) }}"
roles:
- nginx
- hosts: reverseproxy
vars:
nginx: "{{ glob_nginx | default({}) | combine(service_nginx | default({})) | combine(loc_nginx | default({})) }}"
reverseproxy: "{{ glob_reverseproxy | default({}) | combine(service_reverseproxy | default({})) | combine(loc_reverseproxy | default({})) }}"
roles:
- nginx

13
plays/ntp.yml Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env ansible-playbook
---
- hosts: ntp_server
vars:
ntp_server: '{{ glob_ntp_server | combine(loc_ntp_server | default({})) }}'
roles:
- ntp-server
- hosts: debian
vars:
ntp_client: '{{ glob_ntp_client | combine(loc_ntp_client | default({})) }}'
roles:
- ntp-client

7
plays/slapd.yml Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env ansible-playbook
---
- hosts: slapd
vars:
slapd: "{{ glob_slapd | default({}) | combine(service_slapd | default({})) | combine(loc_slapd | default({})) }}"
roles:
- slapd

51
roles/apt/tasks/main.yml Normal file
View File

@ -0,0 +1,51 @@
---
- name: Clear charybde configuration
lineinfile:
state: absent
path: /etc/hosts
regex: "^{{ item }}"
loop:
- "185.230.79.30"
- "2a0c:700:2:0:ea39:35ff:fef0:48c9"
- name: Add mirror.crans.org in /etc/hosts
lineinfile:
state: present
path: /etc/hosts
regex: "^{{ item }}"
line: "{{ item }} mirror.adm.ynerant.fr"
loop:
- "172.16.42.102"
- "fd00::42:4000:ff:fe01:242"
- name: Configure Debian repositories
template:
src: apt/sources.list.j2
dest: /etc/apt/sources.list
owner: root
group: root
mode: 0644
- name: Configure extra repositories
template:
src: apt/sources.list.d/sources.list.j2
dest: "/etc/apt/sources.list.d/{{ item.name }}.list"
owner: root
group: root
mode: 0644
loop: "{{ apt.extra_repositories }}"
- name: Configure pin from future distributions
template:
src: "apt/{{ item[0] }}.d/pin{{ item[1] }}.j2"
dest: "/etc/apt/{{ item[0] }}.d/{{ item[2].key }}{{ item[1] }}"
owner: root
group: root
mode: 0644
with_nested:
- [["sources.list", ".list"], ["preferences", ""]]
- "{{ apt.pin|dict2items }}"
- name: Update APT cache
apt:
update_cache: true

View File

@ -0,0 +1,12 @@
{{ ansible_header | comment }}
Package: *
Pin: release n={{ item[2].key }}
Pin-Priority: 1
{% for package in item[2].value -%}
Package: {{ package }}
Pin: release n={{ item[2].key }}
Pin-Priority: 900
{% endfor -%}

View File

@ -0,0 +1,3 @@
{{ ansible_header | comment }}
deb {{ apt.mirror }}debian {{ item[2].key }} main contrib non-free

View File

@ -0,0 +1,8 @@
{{ ansible_header | comment }}
{% for repo in item.repositories -%}
deb {{ repo.url }} {{ repo.version }} {{ repo.tags }}
{% if repo.src is defined and repo.src -%}
deb-src {{ repo.url }} {{ repo.version }} {{ repo.tags }}
{% endif -%}
{% endfor -%}

View File

@ -0,0 +1,18 @@
{{ ansible_header | comment }}
{% if ansible_distribution_release != "bullseye" %}
{# Debian security does not exist yet for bullseye #}
# Mises à jour de sécurité
deb {{ apt.mirror }}debian-security {{ ansible_distribution_release }}/updates main contrib non-free
{% endif %}
# Dépôt classique
deb {{ apt.mirror }}debian {{ ansible_distribution_release }} main contrib non-free
# Dépôt pour mises à jour fréquentes (volatile)
deb {{ apt.mirror }}debian {{ ansible_distribution_release }}-updates main contrib non-free
{% if apt.backports | default(false) %}
# Backports
deb {{ apt.mirror }}debian {{ ansible_distribution_release }}-backports main contrib non-free
{% endif %}

View File

@ -0,0 +1,52 @@
---
- name: Install certbot and RFC2136 plugin
apt:
update_cache: true
name:
- certbot
- python3-certbot-dns-rfc2136
state: present
register: apt_result
retries: 3
until: apt_result is succeeded
- name: Add DNS credentials
template:
src: letsencrypt/rfc2136.ini.j2
dest: "/etc/letsencrypt/rfc2136.{{ item.certname }}.ini"
mode: 0600
owner: root
loop: "{{ certbot }}"
- name: Add dhparam
template:
src: "letsencrypt/dhparam.j2"
dest: "/etc/letsencrypt/dhparam"
mode: 0600
- name: Create /etc/letsencrypt/conf.d
file:
path: /etc/letsencrypt/conf.d
state: directory
- name: Add Certbot configuration
template:
src: "letsencrypt/conf.d/certname.ini.j2"
dest: "/etc/letsencrypt/conf.d/{{ item.certname }}.ini"
mode: 0644
loop: "{{ certbot }}"
- name: Run certbot
command: certbot --non-interactive --config /etc/letsencrypt/conf.d/{{ item.certname }}.ini certonly
register: certbot_output
changed_when: not "Certificate not yet due for renewal" in certbot_output.stdout
loop: "{{ certbot }}"
- name: Clean old files
file:
path: "{{ item }}"
state: absent
loop:
- "/etc/letsencrypt/options-ssl-nginx.conf"
- "/etc/letsencrypt/ssl-dhparams.pem"
- "/etc/letsencrypt/rfc2136.ini"

View File

@ -0,0 +1,28 @@
{{ ansible_header | comment(decoration='# ') }}
# To generate the certificate, please use the following command
# certbot --config /etc/letsencrypt/conf.d/{{ item.certname }}.ini certonly
# Use a 4096 bit RSA key instead of 2048
rsa-key-size = 4096
# Always use the staging/testing server
# server = https://acme-staging.api.letsencrypt.org/directory
# Uncomment and update to register with the specified e-mail address
email = {{ item.mail }}
# Uncomment to use a text interface instead of ncurses
text = True
# Yes I want to sell my soul and my guinea pig.
agree-tos = True
# Use DNS-01 challenge
authenticator = dns-rfc2136
dns-rfc2136-credentials = /etc/letsencrypt/rfc2136.{{ item.certname }}.ini
dns-rfc2136-propagation-seconds = 30
# Wildcard the domain
cert-name = {{ item.certname }}
domains = {{ item.domains }}

View File

@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
-----END DH PARAMETERS-----

View File

@ -0,0 +1,7 @@
{{ ansible_header | comment(decoration='# ') }}
dns_rfc2136_server = {{ item.dns_rfc2136_server }}
dns_rfc2136_port = 53
dns_rfc2136_name = {{ item.dns_rfc2136_name }}
dns_rfc2136_secret = {{ item.dns_rfc2136_secret }}
dns_rfc2136_algorithm = HMAC-SHA512

View File

@ -5,10 +5,11 @@
- bash
- bash-completion
- bat
- bind-tools
- curl
- "{% if ansible_os_family == 'Debian' %}dnsutils{% else %}bind-tools{% endif %}"
- git
- man
- mtr
- "mtr{% if ansible_os_family == 'Debian' %}-tiny{% endif %}"
- sl
- htop
- patch

View File

@ -21,10 +21,10 @@ alias cd='cd -P'
alias ip='ip -c'
alias less='less -R'
alias toilet='toilet -f mono12 --rainbow'
{% if ansible_os_family == "Archlinux" -%}
alias startx='exec startx'
{% endif %}
alias gst='git status -s'
@ -38,6 +38,9 @@ alias jack="ssh -L 8006:jack.adm.crans.org:8006 jack.adm.crans.org"
alias daniel="ssh -L 8006:daniel.adm.crans.org:8006 daniel.adm.crans.org"
alias vi=vim
{% if ansible_os_family == "Debian" -%}
alias bat=batcat
{% endif -%}
alias cat=bat
# Add some emoji aliases
@ -47,5 +50,7 @@ alias 🚆=sl
alias 🚂=sl
alias 🚅=sl
alias 💿=cd
{% if ansible_os_family == "Archlinux" -%}
{# Personal computer #}
alias 🐿️="cd /home/ynerant/PycharmProjects/SquirrelBattle && venv/bin/python main.py"
{% endif -%}

8
roles/home/README.md Normal file
View File

@ -0,0 +1,8 @@
# HOME-NOUNOUS
Ce rôle permet d'exporter les homes vers les différents serveurs.
## VARS
home_nounous:
ip: l'ip du serveur nfs

31
roles/home/tasks/main.yml Normal file
View File

@ -0,0 +1,31 @@
---
- name: Install NFS client
apt:
update_cache: true
name:
- nfs-common
state: present
register: apt_result
retries: 3
until: apt_result is succeeded
- name: Create directory home
file:
path: /home
state: directory
owner: root
group: user
mode: 0750
- name: Deploy nfs systemd mount
template:
src: systemd/system/home.mount.j2
dest: /etc/systemd/system/home.mount
mode: 0644
- name: Load and activate nfs systemd mount
systemd:
name: home.mount
daemon_reload: true
enabled: true
state: started

View File

@ -0,0 +1,14 @@
{{ ansible_header | comment }}
[Unit]
Description=Mount home
Wants=network-online.target
After=network-online.target
[Mount]
What={{ home.ip }}:{{ home.mountpoint }}
Where=/home
Type=nfs
Options=rw,nosuid
[Install]
WantedBy=multi-user.target

View File

@ -237,5 +237,5 @@ bar {
}
{% if laptop.touchscreen %}
exec xinput --set-prop 13 "libinput Natural Scrolling Enabled" 1
exec xinput --set-prop 14 "libinput Natural Scrolling Enabled" 1
{% endif %}

View File

@ -0,0 +1,10 @@
# LDAP-CLIENT
Configure un client ldap pour les utilisateurs
## VARS
ldap:
- local: si le serveur est installé en local
- servers: la liste des servers ldap a contacté
- base: le search term du ldap

View File

@ -0,0 +1,16 @@
---
- name: Reconfigure libnss-ldapd package
command: dpkg-reconfigure libnss-ldapd -f noninteractive
- name: Restart nslcd service
service:
name: nslcd
state: restarted
# Empty cache when nslcd is restarted
- name: Restart nscd service
service:
name: nscd
state: restarted
ignore_errors: true # Sometimes service do not exist
listen: Restart nslcd service

View File

@ -0,0 +1,50 @@
---
# Install LDAP client packages
- name: Install LDAP client packages
apt:
update_cache: true
name:
- libnss-ldapd
- libpam-ldapd
state: present
register: apt_result
retries: 3
until: apt_result is succeeded
# Configure /etc/nslcd.conf
- name: Configure nslcd
template:
src: nslcd.conf.j2
dest: /etc/nslcd.conf
mode: 0600
notify: Restart nslcd service
# Configure /etc/nsswitch.conf
- name: Configure NSS to use LDAP
lineinfile:
dest: /etc/nsswitch.conf
regexp: "^{{ item }}"
line: "{{ item }} files systemd ldap"
loop:
- "passwd:"
- "group: "
notify: Restart nslcd service
- name: Configure NSS to use LDAP
lineinfile:
dest: /etc/nsswitch.conf
regexp: "^{{ item }}"
line: "{{ item }} files ldap"
loop:
- "shadow: "
- "networks:"
notify: Restart nslcd service
- name: Configure NSS to use LDAP
lineinfile:
dest: /etc/nsswitch.conf
regexp: "^{{ item }}"
line: "{{ item }} files ldap dns"
loop:
- "hosts:"
notify: Restart nslcd service

View File

@ -0,0 +1,38 @@
{{ ansible_header | comment }}
# /etc/nslcd.conf
# nslcd configuration file. See nslcd.conf(5)
# for details.
# The user and group nslcd should run as.
uid nslcd
gid nslcd
# The location at which the LDAP server(s) should be reachable.
{% if 'slapd' in group_names %}
uri ldapi:///
{% else %}
{% for server in ldap.servers %}
uri ldaps://{{ server }}/
{% endfor %}
{% endif %}
# The search base that will be used for all queries.
base {{ ldap.base }}
# The LDAP protocol version to use.
#ldap_version 3
# The DN to bind with for normal lookups.
#binddn cn=annonymous,dc=example,dc=net
#bindpw secret
# The DN used for password modifications by root.
#rootpwmoddn cn=admin,dc=example,dc=com
# SSL options
#ssl off
tls_reqcert allow
tls_cacertfile /etc/ssl/certs/ca-certificates.crt
# The search scope.
#scope sub

View File

@ -0,0 +1,5 @@
---
- name: Reload nginx
systemd:
name: nginx
state: reloaded

128
roles/nginx/tasks/main.yml Normal file
View File

@ -0,0 +1,128 @@
---
- name: Install NGINX
apt:
update_cache: true
name: nginx
register: apt_result
retries: 3
until: apt_result is succeeded
- name: Copy proxypass snippets
template:
src: "nginx/snippets/options-proxypass.conf.j2"
dest: "/etc/nginx/snippets/options-proxypass.conf"
owner: root
group: root
mode: 0644
- name: Copy SSL snippets
template:
src: "nginx/snippets/options-ssl.conf.j2"
dest: "/etc/nginx/snippets/options-ssl.{{ item.name }}.conf"
owner: root
group: root
mode: 0644
loop: "{{ nginx.ssl }}"
- name: Disable default site
file:
dest: "/etc/nginx/sites-enabled/default"
state: absent
- name: Copy reverse proxy sites
when: reverseproxy is defined
template:
src: "nginx/sites-available/{{ item }}.j2"
dest: "/etc/nginx/sites-available/{{ item }}"
owner: root
group: root
mode: 0644
loop:
- reverseproxy
- reverseproxy_redirect_dname
- redirect
notify: Reload nginx
- name: Activate reverse proxy sites
when: reverseproxy is defined
file:
src: "/etc/nginx/sites-available/{{ item }}"
dest: "/etc/nginx/sites-enabled/{{ item }}"
owner: root
group: root
state: link
loop:
- reverseproxy
- reverseproxy_redirect_dname
- redirect
notify: Reload nginx
ignore_errors: "{{ ansible_check_mode }}"
- name: Copy service nginx configuration
when: nginx.servers is defined and nginx.servers|length > 0
template:
src: "nginx/sites-available/service.j2"
dest: "/etc/nginx/sites-available/{{ nginx.service_name }}"
owner: root
group: root
mode: 0644
notify: Reload nginx
- name: Activate local nginx service site
when: nginx.servers is defined and nginx.servers|length > 0
file:
src: "/etc/nginx/sites-available/{{ nginx.service_name }}"
dest: "/etc/nginx/sites-enabled/{{ nginx.service_name }}"
owner: root
group: root
state: link
notify: Reload nginx
ignore_errors: "{{ ansible_check_mode }}"
- name: Copy 50x error page
template:
src: www/html/50x.html.j2
dest: /var/www/html/50x.html
owner: www-data
group: www-data
mode: 0644
- name: Copy robots.txt file
when: nginx.deploy_robots_file
template:
src: www/html/robots.txt.j2
dest: /var/www/html/robots.txt
owner: www-data
group: www-data
mode: 0644
- name: Install passwords
when: nginx.auth_passwd|length > 0
template:
src: nginx/passwd.j2
dest: /etc/nginx/passwd
mode: 0644
- name: Copy 401 error page
when: nginx.auth_passwd|length > 0
template:
src: www/html/401.html.j2
dest: /var/www/html/401.html
owner: www-data
group: www-data
mode: 0644
- name: Indicate role in motd
template:
src: update-motd.d/05-service.j2
dest: /etc/update-motd.d/05-nginx
mode: 0755
- name: Clean old files
file:
path: "{{ item }}"
state: absent
loop:
- "/etc/nginx/snippets/options-ssl.conf"
- "/var/www/custom_401.html"
- "/var/www/robots.txt"

View File

@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
-----END DH PARAMETERS-----

View File

@ -0,0 +1,4 @@
{{ ansible_header | comment }}
{% for user, hash in nginx.auth_passwd.items() -%}
{{ user }}:{{ hash }}
{% endfor -%}

View File

@ -0,0 +1,87 @@
{{ ansible_header | comment }}
{% for site in reverseproxy.redirect_sites %}
# Redirect http://{{ site.from }} to http://{{ site.to }}
server {
listen 80;
listen [::]:80;
server_name {{ site.from }};
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
return 302 http://{{ site.to }}$request_uri;
}
}
# Redirect https://{{ site.from }} to https://{{ site.to }}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name {{ site.from }};
# SSL common conf
include "/etc/nginx/snippets/options-ssl.{{ site.ssl|default(nginx.default_ssl_domain) }}.conf";
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
return 302 https://{{ site.to }}$request_uri;
}
}
{% endfor %}
{# Also redirect for DNAMEs #}
{% for dname in reverseproxy.redirect_dnames %}
{% for site in reverseproxy.redirect_sites %}
{% set from = site.from | regex_replace('crans.org', dname) %}
{% if from != site.from %}
# Redirect http://{{ from }} to http://{{ site.to }}
server {
listen 80;
listen [::]:80;
server_name {{ from }};
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
return 302 http://{{ site.to }}$request_uri;
}
}
# Redirect https://{{ from }} to https://{{ site.to }}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name {{ from }};
# SSL common conf
include "/etc/nginx/snippets/options-ssl.{{ site.ssl|default(nginx.default_ssl_domain) }}.conf";
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
return 302 https://{{ site.to }}$request_uri;
}
}
{% endif %}
{% endfor %}
{% endfor %}

View File

@ -0,0 +1,62 @@
{{ ansible_header | comment }}
# Automatic Connection header for WebSocket support
# See http://nginx.org/en/docs/http/websocket.html
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
{% for site in reverseproxy.reverseproxy_sites %}
# Redirect http://{{ site.from }} to https://{{ site.from }}
server {
listen 80;
listen [::]:80;
server_name {{ site.from }};
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
return 302 https://$host$request_uri;
}
}
# Reverse proxify https://{{ site.from }} to {% if not site.to.startswith("http") %}http://{% endif %}{{ site.to }}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name {{ site.from }};
# SSL common conf
include "/etc/nginx/snippets/options-ssl.{{ site.ssl|default(nginx.default_ssl_domain) }}.conf";
# Log into separate log files
access_log /var/log/nginx/{{ site.from }}.log;
error_log /var/log/nginx/{{ site.from }}_error.log;
# Keep the TCP connection open a bit for faster browsing
keepalive_timeout 70;
# Custom error page
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/html;
}
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
proxy_pass {% if not site.to.startswith("http") %}http://{% endif %}{{ site.to }};
include "/etc/nginx/snippets/options-proxypass.conf";
}
}
{% endfor %}

View File

@ -0,0 +1,47 @@
{{ ansible_header | comment }}
{% for dname in reverseproxy.redirect_dnames %}
{% for site in reverseproxy.reverseproxy_sites %}
{% set from = site.from | regex_replace('crans.org', dname) %}
{% set to = site.from %}
{% if from != site.from %}
# Redirect http://{{ from }} to http://{{ to }}
server {
listen 80;
listen [::]:80;
server_name {{ from }};
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
return 302 http://{{ to }}$request_uri;
}
}
# Redirect https://{{ from }} to https://{{ to }}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name {{ from }};
# SSL common conf
include "/etc/nginx/snippets/options-ssl.{{ site.ssl|default(nginx.default_ssl_domain) }}.conf";
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
return 302 https://{{ to }}$request_uri;
}
}
{% endif %}
{% endfor %}
{% endfor %}

View File

@ -0,0 +1,132 @@
{{ ansible_header | comment }}
# Automatic Connection header for WebSocket support
# See http://nginx.org/en/docs/http/websocket.html
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
{% for upstream in nginx.upstreams -%}
upstream {{ upstream.name }} {
# Path of the server
server {{ upstream.server }};
}
{% endfor -%}
{% if nginx.default_ssl_server -%}
# Redirect all services to the main site
server {
listen 443 default_server ssl;
listen [::]:443 default_server ssl;
include "/etc/nginx/snippets/options-ssl.{{ nginx.default_ssl_domain }}.conf";
server_name _;
charset utf-8;
# Hide Nginx version
server_tokens off;
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
return 302 https://{{ nginx.default_ssl_server }}$request_uri;
}
}
{% endif -%}
{% if nginx.default_server -%}
# Redirect all services to the main site
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
charset utf-8;
# Hide Nginx version
server_tokens off;
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
return 302 http://{{ nginx.default_server }}$request_uri;
}
}
{% endif -%}
{% for server in nginx.servers %}
{% if server.ssl is defined and server.ssl -%}
# Redirect HTTP to HTTPS
server {
listen 80{% if server.default is defined and server.default %} default_server{% endif %};
listen [::]:80{% if server.default is defined and server.default %} default_server{% endif %};
server_name {{ server.server_name|join(" ") }};
charset utf-8;
# Hide Nginx version
server_tokens off;
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
location / {
return 302 https://$host$request_uri;
}
}
{% endif -%}
server {
{% if server.ssl is defined and server.ssl -%}
listen 443{% if server.default is defined and server.default %} default_server{% endif %} ssl;
listen [::]:443{% if server.default is defined and server.default %} default_server{% endif %} ssl;
include "/etc/nginx/snippets/options-ssl.{{ server.ssl }}.conf";
{% else -%}
listen 80{% if server.default is defined and server.default %} default_server{% endif %};
listen [::]:80{% if server.default is defined and server.default %} default_server{% endif %};
{% endif -%}
server_name {{ server.server_name|join(" ") }};
charset utf-8;
# Hide Nginx version
server_tokens off;
{% for realip in nginx.real_ip_from %}
set_real_ip_from {{ realip }};
{% endfor %}
real_ip_header X-Real-Ip;
{% if server.root is defined %}root {{ server.root }};{% endif %}
{% if server.index is defined %}index {{ server.index|join(" ") }};{% endif %}
{% if server.access_log is defined %}access_log {{ server.access_log }};{% endif %}
{% if server.error_log is defined %}error_log {{ server.error_log }};{% endif %}
{% if server.additional_params is defined %}
{% for param in server.additional_params %}
{{ param }};
{% endfor %}
{% endif %}
{% if server.locations is defined %}
{% for location in server.locations %}
location {{ location.filter }} {
{% for param in location.params %}
{{ param }};
{% endfor %}
}
{% endfor %}
{% endif %}
}
{% endfor %}

View File

@ -0,0 +1,18 @@
{{ ansible_header | comment }}
# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info (^/[^/]*)(.*)$;
# check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
# Let NGINX handle errors
fastcgi_intercept_errors on;
include /etc/nginx/fastcgi.conf;
fastcgi_pass unix:/var/run/fcgiwrap.socket;

View File

@ -0,0 +1,19 @@
{{ ansible_header | comment }}
proxy_redirect off;
proxy_set_header Host $host;
# Pass the real client IP
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Tell proxified server that we are HTTPS, fix Wordpress
proxy_set_header X-Forwarded-Proto https;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# For Owncloud WebDav
client_max_body_size 10G;

View File

@ -0,0 +1,17 @@
{{ ansible_header | comment }}
ssl_certificate {{ item.cert }};
ssl_certificate_key {{ item.cert_key }};
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
ssl_dhparam /etc/letsencrypt/dhparam;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Enable OCSP Stapling, point to certificate chain
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate {{ item.trusted_cert }};

View File

@ -0,0 +1,3 @@
#!/usr/bin/tail +14
{{ ansible_header | comment }}
> NGINX a été déployé sur cette machine. Voir /etc/nginx/.

View File

@ -0,0 +1,18 @@
{{ ansible_header | comment('xml') }}
<html>
<head>
<title>Accès refusé</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<h1>Accès refusé</h1>
<p>
Pour éviter le scan des adresses de diffusions par un robot, cette page demande un identifiant et mot de passe.
</p>
<ul>
<li>Identifiant : <em>Stop</em></li>
<li>Mot de passe : <em>Spam</em></li>
</ul>
</body>
</html>

View File

@ -0,0 +1,63 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>502</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
line-height: 1.2;
margin: 0;
}
html {
color: #888;
display: table;
font-family: sans-serif;
height: 100%;
text-align: center;
width: 100%;
}
body {
display: table-cell;
vertical-align: middle;
margin: 2em auto;
}
a {
color: #888;
text-decoration: underline dotted;
}
h1 {
color: #555;
font-size: 2em;
font-weight: 400;
}
p {
margin: 1em auto;
max-width: 480px;
}
@media only screen and (max-width: 280px) {
body, p {
width: 95%;
}
h1 {
font-size: 1.5em;
margin: 0 0 0.3em;
}
}
</style>
</head>
<body>
<h1>502</h1>
<p>Whoops, le service prend trop de temps à répondre…</p>
<p>Essayez de rafraîchir la page. Si le problème persiste, pensez
à contacter <a href="mailto:{{ nginx.contact }}">{{ nginx.who }}</a>.</p>
</body>
</html>

View File

@ -0,0 +1,2 @@
User-agent: *
Disallow: /

View File

@ -0,0 +1,5 @@
---
- name: Restart systemd-timesyncd
service:
name: systemd-timesyncd
state: restarted

View File

@ -0,0 +1,29 @@
---
- name: Clean up ntp
apt:
state: absent
name: ntp
purge: true
register: apt_result
retries: 3
until: apt_result is succeeded
when: "'ntp_server' not in group_names"
- name: Install systemd-timesyncd (bullseye)
apt:
name: systemd-timesyncd
update_cache: true
install_recommends: false
register: apt_result
retries: 3
until: apt_result is succeeded
when:
- "'ntp_server' not in group_names"
- ansible_distribution_release == "bullseye"
- name: Configure NTP
template:
src: systemd/timesyncd.conf.j2
dest: /etc/systemd/timesyncd.conf
notify: Restart systemd-timesyncd
when: "'ntp_server' not in group_names"

View File

@ -0,0 +1,2 @@
[Time]
NTP={{ ntp_client.servers | join(' ') }}

View File

@ -0,0 +1,27 @@
---
- name: Install NTP
apt:
update_cache: true
name: ntp
register: apt_result
retries: 3
until: apt_result is succeeded
- name: Configure NTP daemon
lineinfile:
path: /etc/default/ntp
regexp: '^NTPD_OPTS'
line: NTPD_OPTS='-g -x'
check_mode: no
- name: Configure NTP
template:
src: ntp.conf.j2
dest: /etc/ntp.conf
mode: 0644
- name: Start ntp service
systemd:
name: ntp
enabled: true
state: started

View File

@ -0,0 +1,62 @@
{{ ansible_header | comment }}
# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help
driftfile /var/lib/ntp/ntp.drift
# Leap seconds definition provided by tzdata
leapfile /usr/share/zoneinfo/leap-seconds.list
# Enable this if you want statistics to be logged.
#statsdir /var/log/ntpstats/
statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable
# pool.ntp.org maps to about 1000 low-stratum NTP servers. Your server will
# pick a different set every time it starts up. Please consider joining the
# pool: <http://www.pool.ntp.org/join.html>
pool ntp.crans.org iburst
pool 0.debian.pool.ntp.org iburst
pool 1.debian.pool.ntp.org iburst
pool 2.debian.pool.ntp.org iburst
pool 3.debian.pool.ntp.org iburst
# Access control configuration; see /usr/share/doc/ntp-doc/html/accopt.html for
# details. The web page <http://support.ntp.org/bin/view/Support/AccessRestrictions>
# might also be helpful.
#
# Note that "restrict" applies to both servers and clients, so a configuration
# that might be intended to block requests from certain clients could also end
# up blocking replies from your own upstream servers.
# By default, exchange time with everybody, but don't allow configuration.
restrict -4 default kod notrap nomodify nopeer noquery limited
restrict -6 default kod notrap nomodify nopeer noquery limited
# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict ::1
# Needed for adding pool entries
restrict source notrap nomodify noquery
# Server on adm can sync
restrict 172.16.42.0 mask 255.255.255.0 notrap nomodify
# Clients from this (example!) subnet have unlimited access, but only if
# cryptographically authenticated.
#restrict 192.168.123.0 mask 255.255.255.0 notrust
# If you want to provide time to your local subnet, change the next line.
# (Again, the address is an example only.)
#broadcast 192.168.123.255
# If you want to listen to time broadcasts on your local subnet, de-comment the
# next lines. Please do this only if you trust everybody on the network!
#disable auth
#broadcastclient

13
roles/slapd/README.md Normal file
View File

@ -0,0 +1,13 @@
# SLAPD
Deploie un serveur ldap master ou replica
## VARS
slapd:
- ip : l'ip sur lequel il va installer le serveur ldap
- replica : s'il s'agit d'un master ou d'une replica
- replica_rid : le numéro de replica du serveur
- master_ip : l'ip du master
- replication_credentials : les credientials pour authentifier les replicas
auprès du master

View File

@ -0,0 +1,6 @@
---
- name: Restart slapd
service:
name: slapd.service
state: restarted

View File

@ -0,0 +1,35 @@
---
- name: Install slapd
apt:
update_cache: true
name:
- slapd
register: apt_result
retries: 3
until: apt_result is succeeded
- name: Remove slapd config directory
file:
path: /etc/ldap/slapd.d/
state: absent
- name: Deploy slapd configuration
template:
src: "ldap/{{ item.dest }}.j2"
dest: "/etc/ldap/{{ item.dest }}"
mode: "{{ item.mode }}"
owner: openldap
group: openldap
loop:
- { dest: slapd.conf, mode: "0600" }
#- { dest: ldap.key, mode: "0600" }
#- { dest: ldap.pem, mode: "0644" }
notify: Restart slapd
- name: Deploy ldap services
lineinfile:
path: /etc/default/slapd
regexp: '^SLAPD_SERVICES='
line: 'SLAPD_SERVICES="ldaps://{{ slapd.ip }}/ ldapi:///"'
notify: Restart slapd
check_mode: no

View File

@ -0,0 +1 @@
{{ slapd.private_key }}

View File

@ -0,0 +1 @@
{{ slapd.certificate }}

View File

@ -0,0 +1,202 @@
# This is the main slapd configuration file. See slapd.conf(5) for more
# info on the configuration options.
#######################################################################
# Global Directives:
# Schema and objectClass definitions
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/inetorgperson.schema
# Where the pid file is put. The init.d script
# will not stop the server if you change this.
pidfile /var/run/slapd/slapd.pid
# List of arguments that were passed to the server
argsfile /var/run/slapd/slapd.args
# Read slapd.conf(5) for possible values
loglevel none
# Where the dynamically loaded modules are stored
modulepath /usr/lib/ldap
moduleload back_mdb
{% if not slapd.replica %}
moduleload auditlog
overlay auditlog
auditlog /var/log/openldap/auditlog.log
moduleload constraint
overlay constraint
constraint_attribute description regex {{ slapd.regex }}
restrict=ldap:///ou=hosts,dc=ynerant,dc=fr??one?(objectClass=device)
constraint_attribute uid regex ^ynerant
restrict=ldap:///ou=passwd,dc=ynerant,dc=fr??one?(objectClass=posixAccount)
moduleload syncprov
{% endif %}
# TLS Certificates
#TLSCipherSuite HIGH:MEDIUM:-SSLv2:-SSLv3
#TLSCertificateFile /etc/ldap/ldap.pem
#TLSCertificateKeyFile /etc/ldap/ldap.key
# The maximum number of entries that is returned for a search operation
sizelimit 500
# The tool-threads parameter sets the actual amount of cpu's that is used
# for indexing.
tool-threads 1
#######################################################################
# Specific Backend Directives for mdb:
# Backend specific directives apply to this backend until another
# 'backend' directive occurs
backend mdb
#######################################################################
# Specific Backend Directives for 'other':
# Backend specific directives apply to this backend until another
# 'backend' directive occurs
#backend <other>
#######################################################################
# Specific Directives for database #1, of type mdb:
# Database specific directives apply to this databasse until another
# 'database' directive occurs
database mdb
# The base of your directory in database #1
suffix "dc=ynerant,dc=fr"
# rootdn directive for specifying a superuser on the database. This is needed
# for syncrepl.
rootdn "cn=admin,dc=ynerant,dc=fr"
# Where the database file are physically stored for database #1
directory "/var/lib/ldap"
# The dbconfig settings are used to generate a DB_CONFIG file the first
# time slapd starts. They do NOT override existing an existing DB_CONFIG
# file. You should therefore change these settings in DB_CONFIG directly
# or remove DB_CONFIG and restart slapd for changes to take effect.
# For the Debian package we use 2MB as default but be sure to update this
# value if you have plenty of RAM
#dbconfig set_cachesize 0 2097152 0
# Sven Hartge reported that he had to set this value incredibly high
# to get slapd running at all. See http://bugs.debian.org/303057 for more
# information.
# Number of objects that can be locked at the same time.
#dbconfig set_lk_max_objects 1500
# Number of locks (both requested and granted)
#dbconfig set_lk_max_locks 1500
# Number of lockers
#dbconfig set_lk_max_lockers 1500
# Indexing options for database #1
index objectClass eq
# Save the time that the entry gets modified, for database #1
lastmod on
# Checkpoint the BerkeleyDB database periodically in case of system
# failure and to speed slapd shutdown.
checkpoint 512 30
{% if slapd.replica %}
syncrepl
rid={{ slapd.replica_rid }}
provider=ldaps://{{ slapd.master_ip }}:636
bindmethod=simple
binddn="cn=replicator,dc=ynerant,dc=fr"
credentials={{ slapd.replication_credentials }}
searchbase="dc=ynerant,dc=fr"
scope=sub
schemachecking=on
type=refreshAndPersist
timeout=0
network-timeout=0
retry="30 20 300 +"
tls_reqcert=allow
{% endif %}
{% if slapd.replica %}
# The userPassword by default can be changed
# by the entry owning it if they are authenticated.
# Others should not be able to see it, except the
# admin entry below
# These access lines apply to database #1 only
access to attrs=userPassword,shadowLastChange
by anonymous auth
by * none
# Ensure read access to the base for things like
# supportedSASLMechanisms. Without this you may
# have problems with SASL not knowing what
# mechanisms are available and the like.
# Note that this is covered by the 'access to *'
# ACL below too but if you change that as people
# are wont to do you'll still need this if you
# want SASL (and possible other things) to work
# happily.
access to dn.base="" by * read
# The admin dn has full write access, everyone else
# can read everything.
access to *
by * read
{% else %}
overlay syncprov
# The userPassword by default can be changed
# by the entry owning it if they are authenticated.
# Others should not be able to see it, except the
# admin entry below
# These access lines apply to database #1 only
access to attrs=userPassword,shadowLastChange
by anonymous auth
by self write
by set="[cn=admin,ou=group,dc=ynerant,dc=fr]/memberUid & user/uid" write
by dn="cn=replicator,dc=ynerant,dc=fr" read
by * none
access to attrs=loginShell,mail,telephoneNumber
by self write
by set="[cn=admin,ou=group,dc=ynerant,dc=fr]/memberUid & user/uid" write
by dn="cn=replicator,dc=ynerant,dc=fr" read
by * read
# Ensure read access to the base for things like
# supportedSASLMechanisms. Without this you may
# have problems with SASL not knowing what
# mechanisms are available and the like.
# Note that this is covered by the 'access to *'
# ACL below too but if you change that as people
# are wont to do you'll still need this if you
# want SASL (and possible other things) to work
# happily.
access to dn.base="" by * read
# The admin dn has full write access, everyone else
# can read everything.
access to *
by set="[cn=admin,ou=group,dc=ynerant,dc=fr]/memberUid & user/uid" write
by dn="cn=replicator,dc=ynerant,dc=fr" read
by * read
{% endif %}
#######################################################################
# Specific Directives for database #2, of type 'other' (can be mdb too):
# Database specific directives apply to this databasse until another
# 'database' directive occurs
#database <other>
# The base of your directory for database #2
#suffix "dc=debian,dc=org"

View File

@ -1,13 +1,10 @@
---
- name: Deploy sudoers configuration files
- name: Configure sudoers
template:
src: '{{ item.src }}.j2'
dest: '/etc/{{ item.src }}'
owner: root
group: root
mode: '{{ item.mode }}'
with_items:
- { src: 'sudoers', mode: '0440' }
- { src: 'sudoers.lecture', mode: '0644' }
src: "{{ item }}.j2"
dest: "/etc/{{ item }}"
mode: 0440
loop:
- sudoers.d/custom_passprompt
- sudoers.d/group_privilege
- sudoers

View File

@ -0,0 +1,4 @@
{{ ansible_header | comment }}
# Change prompt
Defaults passprompt_override
Defaults passprompt="[sudo] mot de passe pour %p sur %h: "

View File

@ -0,0 +1,3 @@
{{ ansible_header | comment }}
# Group privilege specification
ADMINS ALL=(ALL:ALL) ALL

View File

@ -1,103 +1,27 @@
{{ ansible_header | comment }}
#
# See the man page for details on how to write a sudoers file.
#
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
## sudoers file.
##
## This file MUST be edited with the 'visudo' command as root.
## Failure to use 'visudo' may result in syntax or file permission errors
## that prevent sudo from running.
##
## See the sudoers man page for the details on how to write a sudoers file.
##
# Host alias specification
User_Alias USERS= %user
User_Alias ADMINS= %admin
##
## Host alias specification
##
## Groups of machines. These may include host names (optionally with wildcards),
## IP addresses, network numbers or netgroups.
# Host_Alias WEBSERVERS = www1, www2, www3
# User alias specification
##
## User alias specification
##
## Groups of users. These may consist of user names, uids, Unix groups,
## or netgroups.
# User_Alias ADMINS = millert, dowdy, mikef
# Cmnd alias specification
##
## Cmnd alias specification
##
## Groups of commands. Often used to group related commands together.
# Cmnd_Alias PROCESSES = /usr/bin/nice, /bin/kill, /usr/bin/renice, \
# /usr/bin/pkill, /usr/bin/top
# Cmnd_Alias REBOOT = /sbin/halt, /sbin/reboot, /sbin/poweroff
# User privilege specification
root ALL=(ALL:ALL) ALL
##
## Defaults specification
##
## You may wish to keep some of the following environment variables
## when running commands via sudo.
##
## Locale settings
# Defaults env_keep += "LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET"
##
## Run X applications through sudo; HOME is used to find the
## .Xauthority file. Note that other programs use HOME to find
## configuration files and this may lead to privilege escalation!
# Defaults env_keep += "HOME"
##
## X11 resource path settings
# Defaults env_keep += "XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH"
##
## Desktop path settings
# Defaults env_keep += "QTDIR KDEDIR"
##
## Allow sudo-run commands to inherit the callers' ConsoleKit session
# Defaults env_keep += "XDG_SESSION_COOKIE"
##
## Uncomment to enable special input methods. Care should be taken as
## this may allow users to subvert the command being run via sudo.
# Defaults env_keep += "XMODIFIERS GTK_IM_MODULE QT_IM_MODULE QT_IM_SWITCHER"
##
## Uncomment to use a hard-coded PATH instead of the user's to find commands
# Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
##
## Uncomment to send mail if the user does not enter the correct password.
# Defaults mail_badpass
##
## Uncomment to enable logging of a command's output, except for
## sudoreplay and reboot. Use sudoreplay to play back logged sessions.
# Defaults log_output
# Defaults!/usr/bin/sudoreplay !log_output
# Defaults!/usr/local/bin/sudoreplay !log_output
# Defaults!REBOOT !log_output
{% if 'virtu' in group_names %}
# Pour vérifier quels vms sont sur quels virtus
USERS ALL=(root:ALL) NOPASSWD:/usr/sbin/qm list
##
## Runas alias specification
##
{% endif %}
# See sudoers(5) for more information on "#include" directives:
##
## User privilege specification
##
root ALL=(ALL) ALL
## Uncomment to allow members of group wheel to execute any command
%wheel ALL=(ALL) ALL
## Same thing without a password
# %wheel ALL=(ALL) NOPASSWD: ALL
## Uncomment to allow members of group sudo to execute any command
# %sudo ALL=(ALL) ALL
## Uncomment to allow any user to run sudo if they know the password
## of the user they are running the command as (root by default).
# Defaults targetpw # Ask for the password of the target user
# ALL ALL=(ALL) ALL # WARNING: only use this together with 'Defaults targetpw'
Defaults lecture=always
Defaults lecture_file=/etc/sudoers.lecture
# toilet -f future --rainbow 'BE NICE' > sudoers.lecture.j2
## Read drop-in files from /etc/sudoers.d
## (the '#' here does not indicate a comment)
#includedir /etc/sudoers.d

View File

@ -1,3 +0,0 @@
┏┓ ┏━╸ ┏┓╻╻┏━╸┏━╸
┣┻┓┣╸ ┃┗┫┃┃ ┣╸
┗━┛┗━╸ ╹ ╹╹┗━╸┗━╸

View File

@ -44,5 +44,3 @@ set whichwrap+=<,>,h,l,[,]
colorscheme elflord
highlight ExtraWhitespace ctermbg=lightgreen guibg=lightgreen
match ExtraWhitespace /\s\+$/
set tw=80

Binary file not shown.

6
vars_plugins/pass.ini Normal file
View File

@ -0,0 +1,6 @@
[pass]
# password_store_dir=/home/ynerant/.password-store
crans_password_store_submodule=.
[pass_become]
all=templier

View File

@ -0,0 +1,6 @@
[pass]
# password_store_dir=/home/me/.password-store
# crans_password_store_submodule=crans
[pass_become]
# all=mdp-root

102
vars_plugins/pass.py Normal file
View File

@ -0,0 +1,102 @@
#!/usr/bin/env python
from functools import lru_cache
from getpass import getpass
import os
from pathlib import Path
import subprocess
import sys
from ansible.module_utils.six.moves import configparser
from ansible.plugins.vars import BaseVarsPlugin
DOCUMENTATION = """
module: pass
vars: vault
version_added: 2.9
short_description: Load vault passwords from pass
description:
- Works exactly as a vault, loading variables from pass.
- Decrypts the YAML file `ansible_vault` from cranspasswords.
- Loads the secret variables.
- Makes use of data caching in order to avoid calling cranspasswords multiple times.
- Uses the local gpg key from the user running ansible on the Control node.
"""
class VarsModule(BaseVarsPlugin):
@staticmethod
@lru_cache
def decrypt_password(name, crans_submodule=False):
"""
Passwords are decrypted from the local password store, then are cached.
By that way, we don't decrypt these passwords everytime.
"""
# Load config
config = configparser.ConfigParser()
config.read(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'pass.ini'))
password_store = Path(config.get('pass', 'password_store_dir',
fallback=os.getenv('PASSWORD_STORE_DIR', Path.home() / '.password-store')))
if crans_submodule:
password_store /= config.get('pass', 'crans_password_store_submodule',
fallback=os.getenv('CRANS_PASSWORD_STORE_SUBMODULE', 'crans'))
full_command = ['gpg', '-d', password_store / f'{name}.gpg']
proc = subprocess.run(full_command, capture_output=True, close_fds=True)
clear_text = proc.stdout.decode('UTF-8')
sys.stderr.write(proc.stderr.decode('UTF-8'))
return clear_text
@staticmethod
@lru_cache
def become_password(entity):
"""
Query the become password that should be used for the given entity.
If entity is the whole group that has no default password,
the become password will be prompted.
The configuration should be given in pass.ini, in the `pass_become`
group. You have only to write `group=pass-filename`.
"""
# Load config
config = configparser.ConfigParser()
config.read(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'pass.ini'))
if config.has_option('pass_become', entity.get_name()):
return VarsModule.decrypt_password(
config.get('pass_become', entity.get_name())).split('\n')[0]
if entity.get_name() == "all":
return getpass("BECOME password: ", stream=None)
return None
def get_vars(self, loader, path, entities):
"""
Get all vars for entities, called by Ansible.
loader: Ansible's DataLoader.
path: Current play's playbook directory.
entities: Host or group names pertinent to the variables needed.
"""
# VarsModule objects are called every time you need host vars, per host,
# and per group the host is part of.
# It is about 6 times per host per task in current state
# of Ansible Crans configuration.
# It is way to much.
# So we cache the data into the DataLoader (see parsing/DataLoader).
passwords = {}
for entity in entities:
# Load vault passwords
if entity.get_name() == 'all':
passwords['vault'] = loader.load(
VarsModule.decrypt_password('ansible_vault', True))
# Load become password
become_password = VarsModule.become_password(entity)
if become_password is not None:
passwords['ansible_become_password'] = become_password
return passwords