Compare commits

...

64 Commits

Author SHA1 Message Date
da79c9264a Unattend-upgrades upgrade also debian-updates and debian-backports
Signed-off-by: Emmy D'Anello <ynerant@emy.lu>
2023-04-09 10:54:16 +02:00
34c7601cf7 Don't use password for nullmailer
Signed-off-by: Emmy D'Anello <ynerant@emy.lu>
2023-04-09 10:50:47 +02:00
fb1b19bcfd testing server got deleted, minecraft server is temporary down
Signed-off-by: Emmy D'Anello <ynerant@emy.lu>
2023-04-03 14:38:43 +02:00
37ccc19e04 Drop useless step
Signed-off-by: Emmy D'Anello <ynerant@emy.lu>
2023-04-03 14:38:43 +02:00
41c9135dfe Galène uses backports
Signed-off-by: Emmy D'Anello <ynerant@emy.lu>
2023-04-03 14:38:43 +02:00
d320cc0a44 Configure unattended-upgrades
Signed-off-by: Emmy D'Anello <ynerant@emy.lu>
2023-04-03 14:38:43 +02:00
0d560218e2 Add Belenios and Galène
Signed-off-by: Emmy D'Anello <ynerant@emy.lu>
2023-04-03 14:38:43 +02:00
f56276b15b Fix URL in header
Signed-off-by: Emmy D'Anello <ynerant@emy.lu>
2023-04-03 13:33:27 +02:00
cf37b94440 Add Belenios and Galène
Signed-off-by: Emmy D'Anello <ynerant@emy.lu>
2023-04-03 13:18:41 +02:00
9169d8e6c6 Add tgvmax
Signed-off-by: Emmy D'Anello <ynerant@crans.org>
2023-02-12 13:45:35 +01:00
9eb88e6417 nupes is on srv-nat, not adh
Signed-off-by: Emmy D'Anello <ynerant@crans.org>
2023-02-12 13:45:29 +01:00
7cfd15a08f Drop deleted hosts
Signed-off-by: Emmy D'Anello <ynerant@crans.org>
2023-01-12 12:52:55 +01:00
414950f4b5 Remove laptop-specific code
Signed-off-by: Emmy D'Anello <ynerant@crans.org>
2023-01-12 12:50:19 +01:00
7f4f846408 Lot of stuff
Signed-off-by: Emmy D'Anello <ynerant@crans.org>
2023-01-12 12:36:32 +01:00
de76ae0085 There is no VM < Bullseye
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2022-07-30 17:34:42 +02:00
a686970b0f [sudo] Replace # by @
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2022-06-27 16:33:42 +02:00
4fe3babc83 bullseye-security exists
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-11-10 11:46:53 +01:00
a1683dbf19 Synapse has Internet
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-22 23:01:17 +02:00
88ac609897 Replace template_path by template_fullpath in Ansible header
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-08 17:03:22 +02:00
2a5f6621b6 Add monitoring
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-08 16:59:10 +02:00
f7de61b6e2 Fix base playbook order
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-04 17:32:50 +02:00
f57b1f1b3e network_interfaces is working for my router
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-04 17:14:30 +02:00
f1ac6f269b Deploy network interfaces from LDAP
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-04 17:02:54 +02:00
50cb4cfc75 Reorder hosts
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-04 15:59:33 +02:00
aef3070586 Welcome Gitea/Nextcloud
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-04 15:57:48 +02:00
89bbc6c070 Add some machines to test Babel/re6stnet
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-04 15:57:08 +02:00
361125e4a5 Deploy nullmailer
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-04 15:56:40 +02:00
b592afcd38 Add some packages
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-04 15:52:24 +02:00
145dccac2d Deploy root password
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-06-04 15:51:04 +02:00
8c4684a450 [nginx] setup nginx
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-25 09:48:58 +02:00
f9491c6553 [certbot] Configure certbot
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-25 08:26:01 +02:00
c0a466db6a Configure sudoers
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 21:01:22 +02:00
3fedc63db3 Mount home directories
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 20:51:07 +02:00
0a85cd22ff Connexion au serveur LDAP
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 19:30:20 +02:00
a8c4bf141b Forget dt for now
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 19:22:17 +02:00
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
6a3010816a Update natural scroll for i3
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 18:49:03 +02:00
e8661bbddb Update slapd server
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 18:48:04 +02:00
571f694ed1 templier is here
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-05-24 18:28:25 +02:00
1115f7d0a8 NTP client/server, prepare slapd
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-29 15:12:28 +02:00
7f39ea724a Read become password from pass
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 10:48:05 +02:00
475fe06fb7 [apt] Better configuration to pin packages
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 10:43:05 +02:00
1d1b31c461 Remove some bash aliases on servers
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 10:34:52 +02:00
8d649970ee Fix common tools
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 10:24:34 +02:00
3ab93fd509 [apt] Update cache
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 00:46:07 +02:00
680b09ca2c Move playbooks in a separate directory
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-08 00:41:19 +02:00
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
7388125008 [apt] Configure APT sources
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-04-07 23:55:10 +02:00
564db32244 Add useful tools for networking
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-22 13:53:13 +01:00
bfbb228d12 Add pacman role
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-21 01:43:12 +01:00
f84085a142 Install patch, jq, obs-studio
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-21 00:42:38 +01:00
7d5c4c9d2d [xorg] Add xorg-xinput
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-20 23:07:31 +01:00
a3ffc713c1 navigateur -> browser
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-20 23:00:26 +01:00
2afba2cda4 Don't use dark theme for GTK
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-18 08:17:40 +01:00
faa42d0789 Remove trailing whitespace
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-18 00:48:31 +01:00
b742395cd4 Fix comments for vim
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-18 00:46:38 +01:00
57b83cb58e Explicit permissions
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-18 00:28:19 +01:00
b0d8cdaf72 Add a lot of ansible headers
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-17 23:38:26 +01:00
7d401e9f00 Fix SSH config
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-17 23:07:30 +01:00
9b0be73500 Add ansible header
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-17 23:03:08 +01:00
be6bc01114 Add some bash aliases
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-03-17 22:45:37 +01:00
988f701433 Install firefox in french
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-29 15:01:49 +01:00
7203cc43ee Use mic key to (un)mute
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-29 01:41:15 +01:00
7af58a6dc7 Clone shirenn's configuration 2021-01-29 01:08:39 +01:00
159 changed files with 3630 additions and 4222 deletions

2
.gitignore vendored
View File

@ -0,0 +1,2 @@
__pycache__
debug.yml

View File

@ -1,41 +1,20 @@
# Ansible configuration
[defaults]
# Explicitely redefined some defaults to make play execution work
roles_path = ./roles
lookup_plugins = ./lookup_plugins
vars_plugins = ./vars_plugins
# Use true Python version
interpreter_python = /usr/bin/python3
# Do not create .retry files
retry_files_enabled = False
# Use inventory
inventory = ./hosts
# Custom header in templates
ansible_managed = Ansible managed, modified on %Y-%m-%d %H:%M:%S by {uid}
# Do not use cows (with cowsay)
nocows = 1
# Do more parallelism
forks = 15
# Some SSH connection will take time
timeout = 60
[privilege_escalation]
# Use sudo to get priviledge access
become = True
# Ask for password
become_ask_pass = True
[diff]
# TO know what changed
always = yes
# Use a separate module to read passwords from pass
become_ask_pass = False
[ssh_connection]
pipelining = True
retries = 3
[diff]
always = yes

View File

@ -1,7 +0,0 @@
#!/usr/bin/env ansible-playbook
---
# Put a common configuration on all servers
- hosts: all
roles:
- baseconfig
- docker

45
group_vars/all/all.yml Normal file
View File

@ -0,0 +1,45 @@
---
# Custom header
dirty: "{% if template_fullpath is defined %}{{ lookup('pipe', 'git diff --quiet -- ' + template_fullpath | quote + ' || echo dirty') }}{% else %}{{ lookup('pipe', 'git diff --quiet || echo dirty') }}{% endif %}"
ansible_header: |
+++++++++++++++++++++++++++++++++++++++++++++++++++
Ansible managed, don't modify the file locally.
See https://git.ynerant.fr/ynerant/templier-ansible.
{% if template_fullpath is defined %}{% set _, rpath = template_fullpath.split('roles/', 1) %}Commit: {% if dirty %}({{dirty}}) {% endif %}{{ lookup('pipe', 'git log -n 1 --pretty=format:%H -- ' + template_fullpath | quote) }}
{% if dirty %}Run by: {{ ansible_env.SUDO_USER }}
{% else %}Author: {{ lookup('pipe', 'git log -n 1 --pretty=format:%an -- ' + template_fullpath | quote) }}
{% endif %}Template: roles/{{ rpath }}
{% else %}
Run by: {{ ansible_env.SUDO_USER }}
Latest commit: {% if dirty %}({{dirty}}) {% endif %}{{ lookup('pipe', 'git rev-parse HEAD') }}
{% endif %}
+++++++++++++++++++++++++++++++++++++++++++++++++++
glob_ldap:
servers:
- 172.16.42.1
base: 'dc=ynerant,dc=fr'
bind:
domains:
- name: ynerant.fr
administrator: ynerant.crans.org
ipv4: 185.230.78.178
ipv6: 2a0c:700:12:0:f21f:afff:fee5:34ca
slave: "" # 51.15.199.212
aliases:
- cloud
- element
- git
- hydrogen
- mailu
- notls
- synapse
- thelounge
- traefik
- translate
- whoami
- www

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

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

View File

@ -0,0 +1,20 @@
glob_network_interfaces:
vlan:
- name: adh
id: 12
gateway: "185.230.78.99"
dns: "{{ query('ldap', 'ip', 'routeur-templier', 'adh') | ipv4 | first }}"
gateway_v6: "2a0c:700:12::ff:fe00:9912"
- name: adm
id: 42
dns: "{{ query('ldap', 'ip', 'routeur-templier', 'adm') | ipv4 | first }}"
- name: srv_nat
id: 43
gateway: "{{ query('ldap', 'ip', 'routeur-templier', 'srv-nat') | ipv4 | first }}"
dns: "{{ query('ldap', 'ip', 'routeur-templier', 'srv-nat') | ipv4 | first }}"
gateway_v6: "{{ query('ldap', 'ip', 'routeur-templier', 'srv-nat') | ipv6 | first }}"
# Deploy only adm by default
interfaces:
adm: eth0

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

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

View File

@ -0,0 +1,6 @@
---
glob_nullmailer:
root: root@ynerant.fr
smtp_server: smtp.adm.ynerant.fr
defaulthost: ynerant.fr
allmailfrom: root@ynerant.fr

View File

@ -0,0 +1,3 @@
---
glob_prometheus_node_exporter:
listen_addr: "{{ query('ldap', 'ip', ansible_hostname, 'adm') | ipv4 | first }}"

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"

10
group_vars/debian.yml Normal file
View File

@ -0,0 +1,10 @@
---
glob_apt:
mirror: "http://mirror.adm.ynerant.fr/"
backports: false
monitoring_mail: "ynerant+apt@emy.lu"
extra_repositories: []
pin: {}
glob_root:
passwd_hash: '{{ vault.root_passwd_hash }}'

7
group_vars/grafana.yml Normal file
View File

@ -0,0 +1,7 @@
---
glob_grafana:
root_url: https://grafana.ynerant.fr
icon: crans_icon_white.svg
ldap_base: "{{ glob_ldap.base }}"
ldap_master_ipv4: "{{ glob_ldap.servers[0] }}"
ldap_user_tree: "ou=passwd,{{ glob_ldap.base }}"

35
group_vars/nginx.yml Normal file
View File

@ -0,0 +1,35 @@
---
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
glob_prometheus_nginx_exporter:
listen_addr: "{{ query('ldap', 'ip', ansible_hostname, 'adm') | ipv4 | first }}"

View File

@ -0,0 +1,9 @@
---
glob_prometheus: {}
glob_ninjabot:
config:
nick: templier
server: irc.crans.org
port: 6667
channel: "#/dev/null"

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"

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: ens18
srv_nat: ens19

View File

@ -0,0 +1,3 @@
---
interfaces:
adm: ens18

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: ens18
srv_nat: ens19

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: eth0
srv_nat: eth1

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: eth0
srv_nat: eth1

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: ens18
srv_nat: ens19

View File

@ -0,0 +1,7 @@
---
interfaces:
adm: ens18
srv_nat: ens19
loc_apt:
backports: true

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: eth0
srv_nat: eth1

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: eth0
srv_nat: eth1

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: ens18
srv_nat: ens19

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: ens18
srv_nat: ens19

View File

@ -0,0 +1,70 @@
---
interfaces:
adm: eth0
srv_nat: eth1
loc_prometheus:
node:
file: targets_node.json
targets: "{{ groups['server'] | select('match', '^.*\\.adm\\.ynerant\\.fr$') | list | sort }}"
config:
- job_name: servers
file_sd_configs:
- files:
- '/etc/prometheus/targets_node.json'
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- source_labels: [__param_target]
target_label: __address__
replacement: '$1:9100'
nginx:
file: targets_nginx.json
targets:
- proxy.adm.ynerant.fr
config:
- job_name: nginx
file_sd_configs:
- files:
- '/etc/prometheus/targets_nginx.json'
relabel_configs:
- source_labels: [__address__]
target_label: instance
- source_labels: [instance]
target_label: __address__
replacement: '$1:9117'
blackbox:
file: targets_blackbox.json
targets:
- https://ynerant.fr/
- https://bibliogram.ynerant.fr/
- https://element.ynerant.fr/
- https://gitea.ynerant.fr/
- https://grafana.ynerant.fr/
- https://hydrogen.ynerant.fr/
- https://nextcloud.ynerant.fr/
- https://mailu.ynerant.fr/
- http://notls.ynerant.fr/
- https://reddit.ynerant.fr/
- https://thelounge.ynerant.fr/
- https://translate.ynerant.fr/
- https://kfet.saperlistpopette.fr/
config:
- job_name: blackbox
file_sd_configs:
- files:
- '/etc/prometheus/targets_blackbox.json'
metrics_path: /probe
params:
module: [http_2xx] # Look for a HTTP 200 response.
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9115

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: eth0
srv_nat: eth1

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: ens18
srv_nat: ens19

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: ens18
srv_nat: ens19

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: ens18
srv_nat: ens19

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: eth0
srv_nat: eth1

View File

@ -0,0 +1,3 @@
---
interfaces:
adm: eth0

View File

@ -0,0 +1,5 @@
---
interfaces:
adm: ens18
adh: ens19
srv_nat: ens20

View File

@ -0,0 +1,8 @@
---
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: adm.ynerant.fr
domains: "*.adm.ynerant.fr"

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: ens18
srv_nat: ens19

View File

@ -0,0 +1,4 @@
---
interfaces:
adm: ens18
srv_nat: ens19

70
hosts
View File

@ -1,3 +1,67 @@
[perso]
templier.adh.crans.org
dt.adh.crans.org
[blackbox]
monitoring.adm.ynerant.fr
[certbot]
proxy.adm.ynerant.fr
templier.adm.ynerant.fr
[debian:children]
server
[grafana]
monitoring.adm.ynerant.fr
[nginx]
nupes.adm.ynerant.fr
tgvmax.adm.ynerant.fr
[nginx:children]
reverseproxy
[ntp_server]
routeur-templier.adm.ynerant.fr
[postfix]
mailu.adm.ynerant.fr
[prometheus]
monitoring.adm.ynerant.fr
[reverseproxy]
proxy.adm.ynerant.fr
[routeur]
routeur-templier.adm.ynerant.fr
[server:children]
virtu
vm
[slapd]
templier.adm.ynerant.fr
[virtu]
templier.adm.ynerant.fr
[vm]
belenios.adm.ynerant.fr
borg.adm.ynerant.fr
dendrite.adm.ynerant.fr
docker.adm.ynerant.fr
dns.adm.ynerant.fr
fosscord.adm.ynerant.fr
galene.adm.ynerant.fr
gitea.adm.ynerant.fr
mailu.adm.ynerant.fr
mastodon.adm.ynerant.fr
#minecraft.adm.ynerant.fr
monitoring.adm.ynerant.fr
nextcloud.adm.ynerant.fr
nupes.adm.ynerant.fr
pad.adm.ynerant.fr
peertube.adm.ynerant.fr
psql.adm.ynerant.fr
proxy.adm.ynerant.fr
routeur-templier.adm.ynerant.fr
tgvmax.adm.ynerant.fr
wireguard.adm.ynerant.fr

Binary file not shown.

206
lookup_plugins/ldap.py Normal file
View File

@ -0,0 +1,206 @@
"""
To use this lookup plugin, you need to pass ldap:
ssh -L 1636:172.16.10.1:636 172.16.10.1
"""
import ipaddress
from ansible.errors import AnsibleError, AnsibleParserError
from ansible.plugins.lookup import LookupBase
from ansible.utils.display import Display
try:
import ldap
except ImportError:
raise AnsibleError("You need to install python3-ldap")
display = Display()
def decode_object(object):
return {attribute: [value.decode('utf-8') for value in object[attribute]] for attribute in object}
class LookupModule(LookupBase):
def __init__(self, **kwargs):
self.base = ldap.initialize('ldaps://localhost:1636/')
self.base.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW)
self.base.set_option(ldap.OPT_X_TLS_NEWCTX, 0)
self.base_dn = 'dc=ynerant,dc=fr'
def query(self, base, scope, filter='(objectClass=*)', attr=None):
"""
Make a LDAP query
query('ldap', 'query', BASE, SCOPE[, FILTER[, ATTR]])
BASE: base dn
SCOPE: 'base', 'one' or 'sub'
FILTER: ldap filter (optional)
ATTR: list of attributes (optional)
"""
scope = { 'base': ldap.SCOPE_BASE, 'one': ldap.SCOPE_ONELEVEL, 'sub': ldap.SCOPE_SUBTREE }[scope]
query_id = self.base.search(f"{base}", scope, filter, attr)
result = self.base.result(query_id)[1]
result = { dn: decode_object(entry) for dn, entry in result }
return result
def ip(self, host, vlan):
"""
Retrieve IP addresses of an interface of a device
query('ldap', 'ip', HOST, VLAN)
"""
if isinstance(vlan, int):
network_query_id = self.base.search(f"ou=networks,{self.base_dn}", ldap.SCOPE_ONELEVEL, f"description={vlan}")
network_result = self.base.result(network_query_id)
vlan = network_result[1][0][1]['cn'][0].decode('utf-8')
if vlan == 'adh':
query_id = self.base.search(f"cn={host}.ynerant.fr,cn={host},ou=hosts,{self.base_dn}", ldap.SCOPE_BASE)
else:
query_id = self.base.search(f"cn={host}.{vlan}.ynerant.fr,cn={host},ou=hosts,{self.base_dn}", ldap.SCOPE_BASE)
result = self.base.result(query_id)
result = result[1][0][1]
result = [res.decode('utf-8') for res in result['ipHostNumber']]
return result
def all_ip(self, host):
"""
Retrieve all IP addresses of a device
query('ldap', 'all_ip', HOST)
"""
interfaces_query_id = self.base.search(f"cn={host},ou=hosts,{self.base_dn}", ldap.SCOPE_ONELEVEL)
interfaces_result = self.base.result(interfaces_query_id)
result = []
for dn, interface in interfaces_result[1]:
for ip in interface['ipHostNumber']:
result.append(ip.decode('utf-8'))
return result
def cn(self, host, vlan):
"""
Retrieve aliases of an interface of a device
query('ldap', 'cn', HOST, VLAN)
"""
if isinstance(vlan, int):
network_query_id = self.base.search(f"ou=networks,{self.base_dn}", ldap.SCOPE_ONELEVEL, f"description={vlan}")
network_result = self.base.result(network_query_id)
vlan = network_result[1][0][1]['cn'][0].decode('utf-8')
if vlan == 'adh':
query_id = self.base.search(f"cn={host}.ynerant.fr,cn={host},ou=hosts,{self.base_dn}", ldap.SCOPE_BASE)
else:
query_id = self.base.search(f"cn={host}.{vlan}.ynerant.fr,cn={host},ou=hosts,{self.base_dn}", ldap.SCOPE_BASE)
result = self.base.result(query_id)
result = result[1][0][1]
result = [res.decode('utf-8') for res in result['cn']]
return result
def all_cn(self, host):
"""
Retrieve all aliases addresses of a device
query('ldap', 'all_cn', HOST)
"""
interfaces_query_id = self.base.search(f"cn={host},ou=hosts,{self.base_dn}", ldap.SCOPE_ONELEVEL)
interfaces_result = self.base.result(interfaces_query_id)
result = []
for dn, interface in interfaces_result[1]:
for cn in interface['cn']:
result.append(cn.decode('utf-8'))
return result
def ssh_keys(self, host):
"""
Retrieve SSH keys of a host
query('ldap', 'ssh_keys', HOST)
"""
host_query_id = self.base.search(f"cn={host},ou=hosts,{self.base_dn}", ldap.SCOPE_BASE)
host_result = self.base.result(host_query_id)[1][0][1]
result = []
if 'description' not in host_result:
return result
for description in host_result['description']:
description = description.decode('utf-8')
key, value = description.split(':', 1)
if key in {'ecdsa-sha2-nistp256', 'ssh-ed25519', 'ssh-dss', 'ssh-rsa'}:
result.append(f'{key} {value}')
return result
def subnet_ipv4(self, subnet):
"""
Retrieve used IP addresses on a subnet
query('ldap', 'subnet_ipv4', SUBNET)
"""
network_query_id = self.base.search(f"cn={subnet},ou=networks,{self.base_dn}", ldap.SCOPE_BASE)
network_result = self.base.result(network_query_id)
network = network_result[1][0][1]
network, hostmask = network['ipNetworkNumber'][0].decode('utf-8'), network['ipNetmaskNumber'][0].decode('utf-8')
subnet = ipaddress.IPv4Network(f"{network}/{hostmask}")
query_id = self.base.search(f"ou=hosts,{self.base_dn}", ldap.SCOPE_SUBTREE, "objectClass=ipHost")
result = self.base.result(query_id)
result = [ip.decode('utf-8') for dn, entry in result[1] for ip in entry['ipHostNumber'] if ipaddress.ip_address(ip.decode('utf-8')) in subnet]
return result
def run(self, terms, variables=None, **kwargs):
if terms[0] == 'query':
result = self.query(*terms[1:])
elif terms[0] == 'ip':
result = self.ip(*terms[1:])
elif terms[0] == 'all_ip':
result = self.all_ip(*terms[1:])
elif terms[0] == 'cn':
result = self.cn(*terms[1:])
elif terms[0] == 'all_cn':
result = self.all_cn(*terms[1:])
elif terms[0] == 'subnet_ipv4':
result = self.subnet_ipv4(*terms[1:])
elif terms[0] == 'ssh_keys':
result = self.ssh_keys(*terms[1:])
elif terms[0] == 'group':
query_id = self.base.search(f"ou=group,{self.base_dn}", ldap.SCOPE_SUBTREE, "objectClass=posixGroup")
result = self.base.result(query_id)
result = result[1]
# query interface attribute
# query('ldap', 'hosts', HOST, VLAN, ATTR)
# HOST: device name
# VLAN: vlan name
# ATTR: attribute
elif terms[0] == 'hosts':
host = terms[1]
vlan = terms[2]
attr = terms[3]
if isinstance(vlan, int):
network_query_id = self.base.search(f"ou=networks,{self.base_dn}", ldap.SCOPE_ONELEVEL, f"description={vlan}")
network_result = self.base.result(network_query_id)
vlan = network_result[1][0][1]['cn'][0].decode('utf-8')
if vlan == 'adh':
query_id = self.base.search(f"cn={host}.ynerant.fr,cn={host},ou=hosts,{self.base_dn}", ldap.SCOPE_BASE)
else:
query_id = self.base.search(f"cn={host}.{vlan}.ynerant.fr,cn={host},ou=hosts,{self.base_dn}", ldap.SCOPE_BASE)
result = self.base.result(query_id)
result = result[1][0][1]
result = [res.decode('utf-8') for res in result[attr]]
elif terms[0] == 'network':
network = terms[1]
query_id = self.base.search(f"cn={network},ou=networks,{self.base_dn}", ldap.SCOPE_BASE, "objectClass=ipNetwork")
result = self.base.result(query_id)
result = result[1][0][1]
return str(ipaddress.ip_network('{}/{}'.format(result['ipNetworkNumber'][0].decode('utf-8'), result['ipNetmaskNumber'][0].decode('utf-8'))))
elif terms[0] == 'zones':
query_id = self.base.search(f"ou=networks,{self.base_dn}", ldap.SCOPE_ONELEVEL, "objectClass=ipNetwork")
result = self.base.result(query_id)
res = []
for _, network in result[1]:
network = network['cn'][0].decode('utf-8')
if network == 'adh':
res.append('ynerant.fr')
else:
res.append(f"{network}.ynerant.fr")
result = res
elif terms[0] == 'vlanid':
network = terms[1]
query_id = self.base.search(f"cn={network},ou=networks,{self.base_dn}", ldap.SCOPE_BASE, "objectClass=ipNetwork")
result = self.base.result(query_id)
result = result[1][0][1]
return int(result['description'][0])
elif terms[0] == 'role':
role = terms[1]
query_id = self.base.search(f"ou=hosts,{self.base_dn}", ldap.SCOPE_ONELEVEL, f"description=role:{role}")
result = self.base.result(query_id)
result = [cn.decode('utf-8') for res in result[1] for cn in res[1]['cn']]
return result

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

23
plays/base.yml Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env ansible-playbook
---
- import_playbook: root.yml
- import_playbook: apt.yml
- import_playbook: network_interfaces.yml
- import_playbook: ntp.yml
- import_playbook: ldap-client.yml
- import_playbook: home.yml
- import_playbook: nullmailer.yml
- import_playbook: monitoring.yml
- hosts: debian
roles:
- sudo
- qemu-guest-agent
- cli-utils
#- hosts: templier.adh.crans.org
# roles:
# - bind
# - docker
# become: yes

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

38
plays/monitoring.yml Executable file
View File

@ -0,0 +1,38 @@
#!/usr/bin/env ansible-playbook
---
# Deploy Prometheus on monitoring server
- hosts: prometheus
vars:
prometheus: "{{ glob_prometheus | default({}) | combine(loc_prometheus | default({})) }}"
alertmanager: "{{ glob_alertmanager | default({}) | combine(loc_alertmanager | default({})) }}"
ninjabot: "{{ glob_ninjabot | default({}) | combine(loc_ninjabot | default({})) }}"
roles:
- prometheus
- prometheus-alertmanager
- ninjabot
# Deploy Grafana on monitoring server
- hosts: grafana
vars:
grafana: "{{ glob_grafana | default({}) | combine(loc_grafana | default({})) }}"
roles:
- grafana
- hosts: blackbox
roles:
- prometheus-blackbox-exporter
# Monitor all hosts
- hosts: server
vars:
prometheus_node_exporter: "{{ glob_prometheus_node_exporter | default({}) | combine(loc_prometheus_node_exporter | default({})) }}"
roles:
- prometheus-node-exporter
# Export nginx metrics
- hosts: nginx
vars:
prometheus_nginx_exporter: "{{ glob_prometheus_nginx_exporter | default({}) | combine(loc_prometheus_nginx_exporter | default({})) }}"
roles:
- prometheus-nginx-exporter

7
plays/network_interfaces.yml Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env ansible-playbook
---
- hosts: vm
vars:
network_interfaces: "{{ glob_network_interfaces | default({}) | combine(loc_network_interfaces | default({})) }}"
roles:
- network-interfaces

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/nullmailer.yml Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env ansible-playbook
---
- hosts: debian,!postfix
vars:
nullmailer: "{{ glob_nullmailer | default({}) | combine(loc_nullmailer | default({})) }}"
roles:
- nullmailer

7
plays/root.yml Executable file
View File

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

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

View File

@ -0,0 +1,32 @@
---
# Install apt-listchanges
- name: Install apt-listchanges
when: ansible_os_family == "Debian"
apt:
name: apt-listchanges
state: present
update_cache: true
register: apt_result
retries: 3
until: apt_result is succeeded
# Send email when there is something new
- name: Configure apt-listchanges
ini_file:
path: /etc/apt/listchanges.conf
no_extra_spaces: true
section: apt
option: "{{ item.option }}"
value: "{{ item.value }}"
state: present
mode: 0644
loop:
- option: confirm
value: "true"
- option: email_address
value: "{{ apt.monitoring_mail }}"
- option: which
value: both
...

View File

@ -0,0 +1,20 @@
---
- name: Install unattended-upgrades
when: ansible_os_family == "Debian"
apt:
name: unattended-upgrades
state: present
update_cache: true
register: apt_result
retries: 3
until: apt_result is succeeded
- name: Configure unattended-upgrades
template:
src: "apt/apt.conf.d/{{ item }}.j2"
dest: "/etc/apt/apt.conf.d/{{ item }}"
owner: root
mode: u=rw,g=r,o=r
loop:
- 50unattended-upgrades
- 20auto-upgrades

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

@ -0,0 +1,58 @@
---
- name: Add mirror.adm.ynerant.fr 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
when: item[2].key != ansible_distribution_release
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: Clear useless pinned configuration
when: item[2].key == ansible_distribution_release
file:
path: "/etc/apt/{{ item[0] }}.d/{{ item[2].key }}{{ item[1] }}"
state: absent
with_nested:
- [["sources.list", ".list"], ["preferences", ""]]
- "{{ apt.pin|dict2items }}"
- name: Update APT cache
apt:
update_cache: true
# APT-List Changes : send email with changelog
- include_tasks: apt-listchanges.yml
# APT Unattended upgrades
- include_tasks: apt-unattended.yml

View File

@ -0,0 +1,4 @@
{{ ansible_header | comment }}
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

View File

@ -0,0 +1,175 @@
{{ ansible_header | comment }}
// Unattended-Upgrade::Origins-Pattern controls which packages are
// upgraded.
//
// Lines below have the format "keyword=value,...". A
// package will be upgraded only if the values in its metadata match
// all the supplied keywords in a line. (In other words, omitted
// keywords are wild cards.) The keywords originate from the Release
// file, but several aliases are accepted. The accepted keywords are:
// a,archive,suite (eg, "stable")
// c,component (eg, "main", "contrib", "non-free")
// l,label (eg, "Debian", "Debian-Security")
// o,origin (eg, "Debian", "Unofficial Multimedia Packages")
// n,codename (eg, "jessie", "jessie-updates")
// site (eg, "http.debian.net")
// The available values on the system are printed by the command
// "apt-cache policy", and can be debugged by running
// "unattended-upgrades -d" and looking at the log file.
//
// Within lines unattended-upgrades allows 2 macros whose values are
// derived from /etc/debian_version:
// ${distro_id} Installed origin.
// ${distro_codename} Installed codename (eg, "buster")
Unattended-Upgrade::Origins-Pattern {
// Codename based matching:
// This will follow the migration of a release through different
// archives (e.g. from testing to stable and later oldstable).
// Software will be the latest available for the named release,
// but the Debian release itself will not be automatically upgraded.
"origin=Debian,codename=${distro_codename},label=Debian";
"origin=Debian,codename=${distro_codename}-updates";
"origin=Debian,codename=${distro_codename}-proposed-updates";
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
"origin=Debian Backports,codename=${distro_codename}-backports,label=Debian Backports"
// Archive or Suite based matching:
// Note that this will silently match a different release after
// migration to the specified archive (e.g. testing becomes the
// new stable).
// "o=Debian,a=stable";
// "o=Debian,a=stable-updates";
// "o=Debian,a=proposed-updates";
// "o=Debian Backports,a=${distro_codename}-backports,l=Debian Backports";
};
// Python regular expressions, matching packages to exclude from upgrading
Unattended-Upgrade::Package-Blacklist {
// The following matches all packages starting with linux-
// "linux-";
// Use $ to explicitely define the end of a package name. Without
// the $, "libc6" would match all of them.
// "libc6$";
// "libc6-dev$";
// "libc6-i686$";
// Special characters need escaping
// "libstdc\+\+6$";
// The following matches packages like xen-system-amd64, xen-utils-4.1,
// xenstore-utils and libxenstore3.0
// "(lib)?xen(store)?";
// For more information about Python regular expressions, see
// https://docs.python.org/3/howto/regex.html
};
// This option allows you to control if on a unclean dpkg exit
// unattended-upgrades will automatically run
// dpkg --force-confold --configure -a
// The default is true, to ensure updates keep getting installed
//Unattended-Upgrade::AutoFixInterruptedDpkg "true";
// Split the upgrade into the smallest possible chunks so that
// they can be interrupted with SIGTERM. This makes the upgrade
// a bit slower but it has the benefit that shutdown while a upgrade
// is running is possible (with a small delay)
//Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::MinimalSteps "true";
// Install all updates when the machine is shutting down
// instead of doing it in the background while the machine is running.
// This will (obviously) make shutdown slower.
// Unattended-upgrades increases logind's InhibitDelayMaxSec to 30s.
// This allows more time for unattended-upgrades to shut down gracefully
// or even install a few packages in InstallOnShutdown mode, but is still a
// big step back from the 30 minutes allowed for InstallOnShutdown previously.
// Users enabling InstallOnShutdown mode are advised to increase
// InhibitDelayMaxSec even further, possibly to 30 minutes.
//Unattended-Upgrade::InstallOnShutdown "false";
// Send email to this address for problems or packages upgrades
// If empty or unset then no email is sent, make sure that you
// have a working mail setup on your system. A package that provides
// 'mailx' must be installed. E.g. "user@example.com"
//Unattended-Upgrade::Mail "";
Unattended-Upgrade::Mail "{{ apt.monitoring_mail }}";
// Set this value to one of:
// "always", "only-on-error" or "on-change"
// If this is not set, then any legacy MailOnlyOnError (boolean) value
// is used to chose between "only-on-error" and "on-change"
//Unattended-Upgrade::MailReport "on-change";
// Remove unused automatically installed kernel-related packages
// (kernel images, kernel headers and kernel version locked tools).
//Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
// Do automatic removal of newly unused dependencies after the upgrade
//Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
// Do automatic removal of unused packages after the upgrade
// (equivalent to apt-get autoremove)
//Unattended-Upgrade::Remove-Unused-Dependencies "false";
Unattended-Upgrade::Remove-Unused-Dependencies "false";
// Automatically reboot *WITHOUT CONFIRMATION* if
// the file /var/run/reboot-required is found after the upgrade
//Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot "true";
// Automatically reboot even if there are users currently logged in
// when Unattended-Upgrade::Automatic-Reboot is set to true
//Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
// If automatic reboot is enabled and needed, reboot at the specific
// time instead of immediately
// Default: "now"
//Unattended-Upgrade::Automatic-Reboot-Time "02:00";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
// Use apt bandwidth limit feature, this example limits the download
// speed to 70kb/sec
//Acquire::http::Dl-Limit "70";
// Enable logging to syslog. Default is False
// Unattended-Upgrade::SyslogEnable "false";
Unattended-Upgrade::SyslogEnable "true";
// Specify syslog facility. Default is daemon
// Unattended-Upgrade::SyslogFacility "daemon";
// Download and install upgrades only on AC power
// (i.e. skip or gracefully stop updates on battery)
// Unattended-Upgrade::OnlyOnACPower "true";
// Download and install upgrades only on non-metered connection
// (i.e. skip or gracefully stop updates on a metered connection)
// Unattended-Upgrade::Skip-Updates-On-Metered-Connections "true";
// Verbose logging
// Unattended-Upgrade::Verbose "false";
// Print debugging information both in unattended-upgrades and
// in unattended-upgrade-shutdown
// Unattended-Upgrade::Debug "false";
// Allow package downgrade if Pin-Priority exceeds 1000
// Unattended-Upgrade::Allow-downgrade "false";
// When APT fails to mark a package to be upgraded or installed try adjusting
// candidates of related packages to help APT's resolver in finding a solution
// where the package can be upgraded or installed.
// This is a workaround until APT's resolver is fixed to always find a
// solution if it exists. (See Debian bug #711128.)
// The fallback is enabled by default, except on Debian's sid release because
// uninstallable packages are frequent there.
// Disabling the fallback speeds up unattended-upgrades when there are
// uninstallable packages at the expense of rarely keeping back packages which
// could be upgraded or installed.
// Unattended-Upgrade::Allow-APT-Mark-Fallback "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,15 @@
{{ ansible_header | comment }}
# Mises à jour de sécurité
deb {{ apt.mirror }}debian-security {{ ansible_distribution_release }}-security main contrib non-free
# 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 %}

File diff suppressed because it is too large Load Diff

View File

@ -1,326 +0,0 @@
# Filename: /etc/skel/.zshrc
# Purpose: config file for zsh (z shell)
# Authors: (c) grml-team (grml.org)
# Bug-Reports: see http://grml.org/bugs/
# License: This file is licensed under the GPL v2 or any later version.
################################################################################
# Nowadays, grml's zsh setup lives in only *one* zshrc file.
# That is the global one: /etc/zsh/zshrc (from grml-etc-core).
# It is best to leave *this* file untouched and do personal changes to
# your zsh setup via ${HOME}/.zshrc.local which is loaded at the end of
# the global zshrc.
#
# That way, we enable people on other operating systems to use our
# setup, too, just by copying our global zshrc to their ${HOME}/.zshrc.
# Adjustments would still go to the .zshrc.local file.
################################################################################
## Aurore host color and white user
zstyle ':prompt:grml:left:items:host' pre '%B%F{red}'
zstyle ':prompt:grml:left:items:host' post '%f%b'
zstyle ':prompt:grml:left:items:user' pre '%B'
zstyle ':prompt:grml:left:items:user' post '%b'
## Settings for umask
#if (( EUID == 0 )); then
# umask 002
#else
# umask 022
#fi
## Now, we'll give a few examples of what you might want to use in your
## .zshrc.local file (just copy'n'paste and uncomment it there):
## Prompt theme extension ##
# Virtualenv support
#function virtual_env_prompt () {
# REPLY=${VIRTUAL_ENV+(${VIRTUAL_ENV:t}) }
#}
#grml_theme_add_token virtual-env -f virtual_env_prompt '%F{magenta}' '%f'
#zstyle ':prompt:grml:left:setup' items rc virtual-env change-root user at host path vcs percent
## ZLE tweaks ##
## use the vi navigation keys (hjkl) besides cursor keys in menu completion
#bindkey -M menuselect 'h' vi-backward-char # left
#bindkey -M menuselect 'k' vi-up-line-or-history # up
#bindkey -M menuselect 'l' vi-forward-char # right
#bindkey -M menuselect 'j' vi-down-line-or-history # bottom
## set command prediction from history, see 'man 1 zshcontrib'
#is4 && zrcautoload predict-on && \
#zle -N predict-on && \
#zle -N predict-off && \
#bindkey "^X^Z" predict-on && \
#bindkey "^Z" predict-off
## press ctrl-q to quote line:
#mquote () {
# zle beginning-of-line
# zle forward-word
# # RBUFFER="'$RBUFFER'"
# RBUFFER=${(q)RBUFFER}
# zle end-of-line
#}
#zle -N mquote && bindkey '^q' mquote
## define word separators (for stuff like backward-word, forward-word, backward-kill-word,..)
#WORDCHARS='*?_-.[]~=/&;!#$%^(){}<>' # the default
#WORDCHARS=.
#WORDCHARS='*?_[]~=&;!#$%^(){}'
#WORDCHARS='${WORDCHARS:s@/@}'
# just type '...' to get '../..'
#rationalise-dot() {
#local MATCH
#if [[ $LBUFFER =~ '(^|/| | |'$'\n''|\||;|&)\.\.$' ]]; then
# LBUFFER+=/
# zle self-insert
# zle self-insert
#else
# zle self-insert
#fi
#}
#zle -N rationalise-dot
#bindkey . rationalise-dot
## without this, typing a . aborts incremental history search
#bindkey -M isearch . self-insert
#bindkey '\eq' push-line-or-edit
## some popular options ##
## add `|' to output redirections in the history
#setopt histallowclobber
## try to avoid the 'zsh: no matches found...'
#setopt nonomatch
## warning if file exists ('cat /dev/null > ~/.zshrc')
#setopt NO_clobber
## don't warn me about bg processes when exiting
#setopt nocheckjobs
## alert me if something failed
#setopt printexitvalue
## with spelling correction, assume dvorak kb
#setopt dvorak
## Allow comments even in interactive shells
#setopt interactivecomments
## compsys related snippets ##
## changed completer settings
#zstyle ':completion:*' completer _complete _correct _approximate
#zstyle ':completion:*' expand prefix suffix
## another different completer setting: expand shell aliases
#zstyle ':completion:*' completer _expand_alias _complete _approximate
## to have more convenient account completion, specify your logins:
#my_accounts=(
# {grml,grml1}@foo.invalid
# grml-devel@bar.invalid
#)
#other_accounts=(
# {fred,root}@foo.invalid
# vera@bar.invalid
#)
#zstyle ':completion:*:my-accounts' users-hosts $my_accounts
#zstyle ':completion:*:other-accounts' users-hosts $other_accounts
## add grml.org to your list of hosts
#hosts+=(grml.org)
#zstyle ':completion:*:hosts' hosts $hosts
## telnet on non-default ports? ...well:
## specify specific port/service settings:
#telnet_users_hosts_ports=(
# user1@host1:
# user2@host2:
# @mail-server:{smtp,pop3}
# @news-server:nntp
# @proxy-server:8000
#)
#zstyle ':completion:*:*:telnet:*' users-hosts-ports $telnet_users_hosts_ports
## the default grml setup provides '..' as a completion. it does not provide
## '.' though. If you want that too, use the following line:
#zstyle ':completion:*' special-dirs true
## aliases ##
## translate
#alias u='translate -i'
## ignore ~/.ssh/known_hosts entries
#alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -o "PreferredAuthentications=keyboard-interactive"'
## global aliases (for those who like them) ##
#alias -g '...'='../..'
#alias -g '....'='../../..'
#alias -g BG='& exit'
#alias -g C='|wc -l'
#alias -g G='|grep'
#alias -g H='|head'
#alias -g Hl=' --help |& less -r'
#alias -g K='|keep'
#alias -g L='|less'
#alias -g LL='|& less -r'
#alias -g M='|most'
#alias -g N='&>/dev/null'
#alias -g R='| tr A-z N-za-m'
#alias -g SL='| sort | less'
#alias -g S='| sort'
#alias -g T='|tail'
#alias -g V='| vim -'
## instead of global aliase it might be better to use grmls $abk assoc array, whose contents are expanded after pressing ,.
#$abk[SnL]="| sort -n | less"
## get top 10 shell commands:
#alias top10='print -l ${(o)history%% *} | uniq -c | sort -nr | head -n 10'
## Execute \kbd{./configure}
#alias CO="./configure"
## Execute \kbd{./configure --help}
#alias CH="./configure --help"
## miscellaneous code ##
## Use a default width of 80 for manpages for more convenient reading
#export MANWIDTH=${MANWIDTH:-80}
## Set a search path for the cd builtin
#cdpath=(.. ~)
## variation of our manzsh() function; pick you poison:
#manzsh() { /usr/bin/man zshall | most +/"$1" ; }
## Switching shell safely and efficiently? http://www.zsh.org/mla/workers/2001/msg02410.html
#bash() {
# NO_SWITCH="yes" command bash "$@"
#}
#restart () {
# exec $SHELL $SHELL_ARGS "$@"
#}
## Handy functions for use with the (e::) globbing qualifier (like nt)
#contains() { grep -q "$*" $REPLY }
#sameas() { diff -q "$*" $REPLY &>/dev/null }
#ot () { [[ $REPLY -ot ${~1} ]] }
## get_ic() - queries imap servers for capabilities; real simple. no imaps
#ic_get() {
# emulate -L zsh
# local port
# if [[ ! -z $1 ]] ; then
# port=${2:-143}
# print "querying imap server on $1:${port}...\n";
# print "a1 capability\na2 logout\n" | nc $1 ${port}
# else
# print "usage:\n $0 <imap-server> [port]"
# fi
#}
## List all occurrences of programm in current PATH
#plap() {
# emulate -L zsh
# if [[ $# = 0 ]] ; then
# echo "Usage: $0 program"
# echo "Example: $0 zsh"
# echo "Lists all occurrences of program in the current PATH."
# else
# ls -l ${^path}/*$1*(*N)
# fi
#}
## Find out which libs define a symbol
#lcheck() {
# if [[ -n "$1" ]] ; then
# nm -go /usr/lib/lib*.a 2>/dev/null | grep ":[[:xdigit:]]\{8\} . .*$1"
# else
# echo "Usage: lcheck <function>" >&2
# fi
#}
## Download a file and display it locally
#uopen() {
# emulate -L zsh
# if ! [[ -n "$1" ]] ; then
# print "Usage: uopen \$URL/\$file">&2
# return 1
# else
# FILE=$1
# MIME=$(curl --head $FILE | \
# grep Content-Type | \
# cut -d ' ' -f 2 | \
# cut -d\; -f 1)
# MIME=${MIME%$'\r'}
# curl $FILE | see ${MIME}:-
# fi
#}
## Memory overview
#memusage() {
# ps aux | awk '{if (NR > 1) print $5;
# if (NR > 2) print "+"}
# END { print "p" }' | dc
#}
## print hex value of a number
#hex() {
# emulate -L zsh
# if [[ -n "$1" ]]; then
# printf "%x\n" $1
# else
# print 'Usage: hex <number-to-convert>'
# return 1
# fi
#}
## log out? set timeout in seconds...
## ...and do not log out in some specific terminals:
#if [[ "${TERM}" == ([Exa]term*|rxvt|dtterm|screen*) ]] ; then
# unset TMOUT
#else
# TMOUT=1800
#fi
## associate types and extensions (be aware with perl scripts and anwanted behaviour!)
#check_com zsh-mime-setup || { autoload zsh-mime-setup && zsh-mime-setup }
#alias -s pl='perl -S'
## ctrl-s will no longer freeze the terminal.
#stty erase "^?"
## you want to automatically use a bigger font on big terminals?
#if [[ "$TERM" == "xterm" ]] && [[ "$LINES" -ge 50 ]] && [[ "$COLUMNS" -ge 100 ]] && [[ -z "$SSH_CONNECTION" ]] ; then
# large
#fi
## Some quick Perl-hacks aka /useful/ oneliner
#bew() { perl -le 'print unpack "B*","'$1'"' }
#web() { perl -le 'print pack "B*","'$1'"' }
#hew() { perl -le 'print unpack "H*","'$1'"' }
#weh() { perl -le 'print pack "H*","'$1'"' }
#pversion() { perl -M$1 -le "print $1->VERSION" } # i. e."pversion LWP -> 5.79"
#getlinks () { perl -ne 'while ( m/"((www|ftp|http):\/\/.*?)"/gc ) { print $1, "\n"; }' $* }
#gethrefs () { perl -ne 'while ( m/href="([^"]*)"/gc ) { print $1, "\n"; }' $* }
#getanames () { perl -ne 'while ( m/a name="([^"]*)"/gc ) { print $1, "\n"; }' $* }
#getforms () { perl -ne 'while ( m:(\</?(input|form|select|option).*?\>):gic ) { print $1, "\n"; }' $* }
#getstrings () { perl -ne 'while ( m/"(.*?)"/gc ) { print $1, "\n"; }' $*}
#showINC () { perl -e 'for (@INC) { printf "%d %s\n", $i++, $_ }' }
#vimpm () { vim `perldoc -l $1 | sed -e 's/pod$/pm/'` }
#vimhelp () { vim -c "help $1" -c on -c "au! VimEnter *" }
## END OF FILE #################################################################

View File

@ -1,39 +0,0 @@
#!/bin/sh
# {{ ansible_managed }}
# Pretty uptime
upSeconds="$(/usr/bin/cut -d. -f1 /proc/uptime)"
mins=$((${upSeconds}/60%60))
hours=$((${upSeconds}/3600%24))
days=$((${upSeconds}/86400))
UPTIME=`printf "%d jours, %02dh%02dm" "$days" "$hours" "$mins"`
# RAM
RAM=`free -m | awk 'NR==2{printf "%s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 }'`
DISK=`df -h | awk '$NF=="/"{printf "%d/%dGB (%s)\n", $3,$2,$5}'`
# Text font
bold=$(tput bold)
normal=$(tput sgr0)
# Logo
cat << EOF

      ${bold}Uptime${normal} : ${UPTIME}
    ${bold}Mémoire${normal} : ${RAM}
        ${bold}Disque racine${normal} : ${DISK}
       
          
           
          
          
       
       
         
         
         
           
        
   ${bold}Aurore${normal}    
EOF

View File

@ -1,3 +0,0 @@
#!/bin/sh
# {{ ansible_managed }}
uname -snrvm

View File

@ -1,4 +0,0 @@
---
# Reconfigure locales when conf changes
- name: Reconfigure locales
command: dpkg-reconfigure locales -f noninteractive

View File

@ -1,52 +0,0 @@
---
- name: Install basic tools
apt:
name:
- apt # better than apt-get
- aptitude # nice to have for Ansible
- bash-completion # because bash
- curl # better than wget
- git # code versioning
- htop # better than top
- less # i like cats
- sudo # i am god
- tmux # better than screen
- tree # create a graphical tree of files
- vim # better than nano
- molly-guard # prevent reboot
- ntp # network time sync
- emacs-nox # for maman
update_cache: true
register: apt_result
retries: 3
until: apt_result is succeeded
# Pimp my server
- name: Customize motd
copy:
src: "update-motd.d/{{ item }}"
dest: "/etc/update-motd.d/{{ item }}"
mode: 0755
loop:
- 00-logo
- 10-uname
- name: Remove Debian warranty motd
file:
path: /etc/motd
state: absent
# Patriotisme
- name: Ensure French UTF-8 locale exists
locale_gen:
name: fr_FR.UTF-8
state: present
# Fix LC_CTYPE="C"
- name: Select default locale
debconf:
name: locales
question: locales/default_environment_locale
value: fr_FR.UTF-8
vtype: select
notify: Reconfigure locales

View File

@ -0,0 +1,6 @@
---
- name: Restart bind
service:
name: bind9
state: restarted

23
roles/bind/tasks/main.yml Normal file
View File

@ -0,0 +1,23 @@
---
- name: Queries apt to install bind9
apt:
name:
- bind9
register: pkg_result
retries: 3
until: pkg_result is succeeded
notify: Restart bind
- name: Deploy named local configuration
template:
src: 'named.conf.local.j2'
dest: '/etc/bind/named.conf.local'
notify: Restart bind
- name: Deploy per-site configuration
template:
src: 'db.j2'
dest: '/var/lib/bind/{{ item.name }}/db'
with_items: '{{ bind.domains }}'
notify: Restart bind

View File

@ -0,0 +1,21 @@
$TTL 3600
@ IN SOA dns {{ item.administrator }}. (
{{ '%Y%m%d%H' | strftime }} ;Serial
3600 ;Refresh
1800 ;Retry
3600000 ;Expire
172800 ;Minimum
)
{{ item.name }}. IN NS dns
{{ item.name }}. IN NS slave
{{ item.name }}. IN A {{ item.ipv4 }}
{{ item.name }}. IN AAAA {{ item.ipv6 }}
dns IN A {{ item.ipv4 }}
dns IN AAAA {{ item.ipv6 }}
slave IN A {{ item.slave }}
{% for alias in item.aliases %}
{{ alias }} IN CNAME @
{% endfor %}

View File

@ -0,0 +1,18 @@
{{ ansible_header | comment(decoration='//') }}
//
// Do any local configuration here
//
// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";
{% for domain in bind.domains %}
zone "{{ domain.name }}" {
type master;
file "/var/lib/bind/{{ domain.name }}/db";
notify yes;
allow-transfer { {{ domain.slave }}; };
};
{% endfor %}

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

@ -0,0 +1,26 @@
---
- name: Install useful utilities
package:
name:
- bash
- bash-completion
- bat
- curl
- dnsutils
- git
- htop
- man
- molly-guard
- mtr-tiny
- needrestart
- patch
- rsync
- sl
- sudo
- tmux
- traceroute
- tree
- vim
register: pkg_result
retries: 3
until: pkg_result is succeeded

View File

@ -15,4 +15,6 @@
template:
src: update-motd.d/05-service.j2
dest: /etc/update-motd.d/05-docker
owner: root
group: root
mode: 0755

View File

@ -1,3 +1,3 @@
#!/bin/sh
# {{ ansible_managed }}
{{ ansible_header | comment }}
echo "> Les recettes Docker-compose se trouvent dans /var/local/ansible-docker"

View File

@ -0,0 +1,5 @@
---
- name: Restart grafana
service:
name: grafana-server
state: restarted

View File

@ -0,0 +1,100 @@
---
- name: Install GPG
apt:
name: gnupg
state: present
register: apt_result
retries: 3
until: apt_result is succeeded
- name: Import Grafana GPG signing key
apt_key:
url: https://packages.grafana.com/gpg.key
state: present
validate_certs: false
register: apt_key_result
retries: 3
until: apt_key_result is succeeded
- name: Add Grafana repository
apt_repository:
repo: deb http://mirror.adm.ynerant.fr/grafana/oss/deb stable main
state: present
update_cache: true
- name: Install Grafana
apt:
name: grafana
state: present
register: apt_result
retries: 3
until: apt_result is succeeded
- name: Configure Grafana
ini_file:
path: /etc/grafana/grafana.ini
section: "{{ item.section }}"
option: "{{ item.option }}"
value: "{{ item.value }}"
mode: 0640
loop:
- section: server
option: root_url
value: "{{ grafana.root_url }}"
- section: analytics
option: reporting_enabled
value: "false"
- section: analytics
option: check_for_updates
value: "false"
- section: security
option: disable_initial_admin_creation
value: "true"
- section: security
option: cookie_secure
value: "true"
- section: snapshots
option: external_enabled
value: "false"
- section: users
option: allow_sign_up
value: "false"
- section: users
option: allow_org_create
value: "false"
- section: auth.anonymous
option: enabled
value: "true"
- section: auth.anonymous
option: hide_version
value: "true"
- section: auth.basic # Only LDAP auth
option: enabled
value: "false"
- section: auth.ldap
option: enabled
value: "true"
- section: alerting
option: enabled
value: "false"
notify: Restart grafana
- name: Configure Grafana LDAP
template:
src: ldap.toml.j2
dest: /etc/grafana/ldap.toml
mode: 0640
notify: Restart grafana
- name: Enable and start Grafana
systemd:
name: grafana-server
enabled: true
state: started
daemon_reload: true
- name: Indicate role in motd
template:
src: update-motd.d/05-service.j2
dest: /etc/update-motd.d/05-grafana
mode: 0755

View File

@ -0,0 +1,47 @@
{{ ansible_header | comment }}
# To troubleshoot and get more log info enable ldap debug logging in grafana.ini
# [log]
# filters = ldap:debug
[[servers]]
# Ldap server host (specify multiple hosts space separated)
host = "{{ grafana.ldap_master_ipv4 }}"
# Default port is 389 or 636 if use_ssl = true
port = 636
# Set to true if ldap server supports TLS
use_ssl = true
# Set to true if connect ldap server with STARTTLS pattern (create connection in insecure, then upgrade to secure connection with TLS)
start_tls = false
# set to true if you want to skip ssl cert validation
ssl_skip_verify = true
# set to the path to your root CA certificate or leave unset to use system defaults
# root_ca_cert = "/path/to/certificate.crt"
# Authentication against LDAP servers requiring client certificates
# client_cert = "/path/to/client.crt"
# client_key = "/path/to/client.key"
# Use direct bind
bind_dn = "uid=%s,{{ grafana.ldap_user_tree }}"
# Useless as we are doing direct bind,
# but without LDAP auth hang
search_filter = "(uid=%s)"
search_base_dns = ["ou=passwd,dc=ynerant,dc=fr"]
## For Posix or LDAP setups that does not support member_of attribute you can define the below settings
## Please check grafana LDAP docs for examples
group_search_filter = "(&(objectClass=posixGroup)(memberUid=%s))"
group_search_base_dns = ["ou=group,{{ grafana.ldap_base }}"]
group_search_filter_user_attribute = "cn"
# Specify names of the ldap attributes your ldap uses
[servers.attributes]
name = "givenName"
surname = "sn"
username = "uid"
email = "mail"
# All LDAP members can edit
[[servers.group_mappings]]
group_dn = "*"
org_role = "Admin"

View File

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

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

@ -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,28 @@
---
- name: Install vlan support
apt:
update_cache: true
name: vlan
state: present
register: apt_result
retries: 3
until: apt_result is succeeded
- name: Deploy default interfaces config
template:
src: network/interfaces.j2
dest: /etc/network/interfaces
mode: 0644
- name: Remove cloud-init interface configuration
file:
path: /etc/network/interfaces.d/50-cloud-init
state: absent
- name: Deploy interfaces config
template:
src: "network/interfaces.d/ifalias.j2"
dest: "/etc/network/interfaces.d/{{ '%02d' | format(item.id) }}-{{ item.name | replace('_', '-') }}"
mode: 0644
when: item.name in interfaces
loop: "{{ network_interfaces.vlan }}"

View File

@ -0,0 +1,55 @@
{{ ansible_header | comment }}
{% set vlan_name = (item.name | replace('_', '-')) %}
{% set subnet_network = (query('ldap', 'network', vlan_name) | ipaddr('network')) %}
{% set subnet_netmask = (query('ldap', 'network', vlan_name) | ipaddr('netmask')) %}
{% set ips = query('ldap', 'ip', ansible_hostname, vlan_name) %}
{% if (ips | ipv4 | length) > 0 %}
auto {{ interfaces[item.name] }}
iface {{ interfaces[item.name] }} inet static
{% for ip in (ips | ipv4) %}
address {{ ip }}
{% endfor %}
network {{ subnet_network }}
netmask {{ subnet_netmask }}
{% if item.gateway is defined and item.gateway not in (ips | ipv4) %}
gateway {{ item.gateway }}
{% endif %}
{% if item.metric is defined %}
metric {{ item.metric }}
{% endif %}
{% if item.dns is defined %}
dns-nameservers {{ item.dns }}
{% endif %}
{% if vlan_name == 'srv' %}
dns-search ynerant.fr
{% else %}
dns-search {{ vlan_name }}.ynerant.fr
{% endif %}
up /sbin/ip link set $IFACE alias {{ vlan_name }}
{% if ansible_local.interfaces.sup_if_4 is defined %}
{% if interfaces[item.name] in ansible_local.interfaces.sup_if_4 %}
{% for line in ansible_local.interfaces.sup_if_4[interfaces[item.name]] %}
{{ line }}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}
{% if (ips | ipv6 | length) > 0 %}
iface {{ interfaces[item.name] }} inet6 static
{% for ip in (ips | ipv6) %}
address {{ ip }}/64
{% endfor %}
{% if item.gateway_v6 is defined and item.gateway_v6 not in (ips | ipv6) %}
gateway {{ item.gateway_v6 }}
{% endif %}
accept_ra 0
{% if ansible_local.interfaces.sup_if_6 is defined %}
{% if interfaces[item.name] in ansible_local.interfaces.sup_if_6 %}
{% for line in ansible_local.interfaces.sup_if_6[interfaces[item.name]] %}
{{ line }}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,10 @@
{{ ansible_header | comment }}
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback

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 %}

Some files were not shown because too many files have changed in this diff Show More