J'avais besoin de mettre en place un partage de fichiers sur mon réseau. Étant dans un environnement full GNU/Linux mon choix s'est naturelement porté sur NFS.
Malheuresement, par conception, ce protocole n'est que très peu sécurisé. Le seul élément de protection que l'on peut mettre en place est le filtrage par adresse ip ce qui peut être considéré comme très faible parce qu'il n'y a pas d'authentification et que les flux circulent en clair (pas de chiffrement).
Il existe deux possibilités pour combler ces lacunes : mettre en place un vpn ou utiliser kerberos. Comme je n'ai jamais travaillé dessus j'ai pensé que c'était l'occasion de m'y mettre. J'aurais mieux fait de me couper une cou… C'est très facile!
allow-hotplug ens192
iface ens192 inet static
address 192.168.1.100
netmask 255.255.255.0
gateway 192.168.1.254
dns-nameservers 192.168.1.254
root@debian:~# apt update && apt install nfs-kernel-server nfs-common krb5-user libpam-krb5 krb5-admin-server krb5-kdc
Note : on pourra répondre STD.LOCAL et nfs.std.local aux questions posées. En fait ça n'a pas d'importance puisque les paramètres seront modifiés ultérieurement.
root@debian:~# groupadd nfs
root@debian:~# usermod -a -G nfs nobody
root@debian:~# mkdir /nfs
root@debian:~# chmod 770 /nfs && chgrp nfs /nfs
192.168.1.100 nfs.std.local nfs
192.168.1.10 arch.std.local arch
192.168.1.11 debian.std.local debian
/nfs *(rw,sync,anongid=1001,root_squash,no_subtree_check,sec=krb5p)
/nfs 192.168.1.10(rw,sync,anongid=1001,root_squash,no_subtree_check,sec=krb5p) 192.168.1.11(rw,sync,anongid=1001,root_squash,no_subtree_check,sec=krb5p)
NEED_SVCGSSD=yes
root@debian:~# systemctl restart nfs-kernel-server.service && exportfs -arv
[libdefaults]
default_realm = STD.LOCAL
kdc_timesync = 1
ccache_type = 4
forwardable = true
proxiable = true
fcc-mit-ticketflags = true
allow_weak_crypto = false
[realms]
STD.LOCAL = {
kdc = nfs.std.local
admin_server = nfs.std.local
default_domain = std.local
}
[domain_realm]
.std.local = STD.LOCAL
std.local = STD.LOCAL
[logging]
kdc = SYSLOG:NOTICE
admin_server = SYSLOG:NOTICE
default = SYSLOG:NOTICE
root@debian:~# kdb5_util -r STD.LOCAL create -s
You will be prompted for the database Master Password.
It is important that you NOT FORGET this password.
Enter KDC database master key: MasterOfTheDomain:p
Re-enter KDC database master key to verify: MasterOfTheDomain:p
#*/admin@STD.LOCAL * -> moins restrictif
kdcadmin/admin@STD.LOCAL *
root@debian:~# systemctl start krb5-kdc.service
root@debian:~# systemctl start krb5-admin-server.service
root@debian:~# kadmin.local
Authenticating as principal root/admin@STD.LOCAL with password.
kadmin.local: add_principal kdcadmin/admin@STD.LOCAL
No policy specified for kdcadmin/admin@STD.LOCAL; defaulting to no policy
Enter password for principal "kdcadmin/admin@STD.LOCAL":$superKDC$2000
Re-enter password for principal "kdcadmin/admin@STD.LOCAL":$superKDC$2000
Principal "kdcadmin/admin@STD.LOCAL" created.
kadmin: exit
root@debian:~# kadmin.local
Authenticating as principal root/admin@STD.LOCAL with password.
kadmin.local: add_principal nfsuser@STD.LOCAL
No policy specified for nfsuser@STD.LOCAL; defaulting to no policy
Enter password for principal "nfsuser@STD.LOCAL":NFScher$$
Re-enter password for principal "nfsuser@STD.LOCAL":NFScher$$
Principal "nfsuser@STD.LOCAL" created.
kadmin: exit
root@debian:~# kadmin.local
kadmin.local: addprinc -randkey nfs/nfs.std.local@STD.LOCAL
No policy specified for nfs/nfs.std.local@STD.LOCAL; defaulting to no policy
Principal "nfs/nfs.std.local@STD.LOCAL" created.
kadmin.local: addprinc -randkey nfs/arch.std.local@STD.LOCAL
No policy specified for nfs/arch.std.local@STD.LOCAL; defaulting to no policy
Principal "nfs/arch.std.local@STD.LOCAL" created.
kadmin.local: addprinc -randkey nfs/debian.std.local@STD.LOCAL
No policy specified for nfs/debian.std.local@STD.LOCAL; defaulting to no policy
Principal "nfs/debian.std.local@STD.LOCAL" created.
kadmin: exit
root@debian:~# kadmin.local
kadmin.local: ktadd nfs/nfs.std.local
kadmin.local: ktadd nfs/arch.std.local
kadmin.local: ktadd nfs/debian.std.local
kadmin: exit
root@debian:~# reboot
[root@arch ~]# pacman -S nfs-utils
[root@arch ~]# systemctl enable nfs-client.target
[root@arch ~]# systemctl start nfs-client.target
192.168.1.100 nfs.std.local nfs
192.168.1.10 arch.std.local arch
192.168.1.11 debian.std.local debian
[libdefaults]
default_realm = STD.LOCAL
kdc_timesync = 1
ccache_type = 4
forwardable = true
proxiable = true
fcc-mit-ticketflags = true
allow_weak_crypto = false
[realms]
STD.LOCAL = {
kdc = nfs.std.local
admin_server = nfs.std.local
default_domain = std.local
}
[domain_realm]
.std.local = STD.LOCAL
std.local = STD.LOCAL
Pour ce faire nous pouvons au choix copier le fichier /etc/krb5.keytab depuis le serveur ou utiliser Kerberos sur le client pour le faire.
[root@arch ~]# kadmin -p kdcadmin/admin@STD.LOCAL
Authenticating as principal kdcadmin/admin@STD.LOCAL with password.
Password for kdcadmin/admin@STD.LOCAL: $superKDC$2000
kadmin: ktadd nfs/arch.std.local
Entry for principal nfs/arch.std.local with kvno 3, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/arch.std.local with kvno 3, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
kadmin: exit
Note : si l'on ne redémarre pas l'erreur mount.nfs: Operation not permitted apparaitra lors du montage.
[root@arch ~]# reboot
[root@arch ~]# mkdir /mnt/nfs
[root@arch ~]# mount -t nfs -o sec=krb5p nfs.std.local:/nfs /mnt/nfs/
Note : Ici le partage devrait être accessible depuis l'utilisateur root par contre le message impossible d'ouvrir le répertoire '/mnt/nfs/': Panne d'accès au fichier apparait depuis un simple utilisateur. Il nous faut ici un ticket kerberos.
[user@arch ~]$ kinit nfsuser@STD.LOCAL
Password for nfsuser@STD.LOCAL: NFScher$$
Nous pouvons maintenant avoir accès au partage depuis notre utilisateur.
[user@arch ~]$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: nfsuser@STD.LOCAL
Valid starting Expires Service principal
18/09/2022 20:14:38 19/09/2022 06:14:38 krbtgt/STD.LOCAL@STD.LOCAL
renew until 19/09/2022 15:14:33
nfs.std.local:/nfs /mnt/nfs nfs defaults,timeo=900,retrans=5,_netdev,sec=krb5p,user,noauto 0 0
root@debian:~# apt update && apt install nfs-common krb5-user
Note : on pourra répondre STD.LOCAL et nfs.std.local aux questions posées. En fait ça n'a pas d'importance puisque les paramètres seront modifiés ultérieurement.
root@debian:~# systemctl enable nfs-client.target
root@debian:~# systemctl start nfs-client.target
192.168.1.100 nfs.std.local nfs
192.168.1.10 arch.std.local arch
192.168.1.11 debian.std.local debian
[libdefaults]
default_realm = STD.LOCAL
kdc_timesync = 1
ccache_type = 4
forwardable = true
proxiable = true
fcc-mit-ticketflags = true
allow_weak_crypto = false
[realms]
STD.LOCAL = {
kdc = nfs.std.local
admin_server = nfs.std.local
default_domain = std.local
}
[domain_realm]
.std.local = STD.LOCAL
std.local = STD.LOCAL
Pour ce faire nous pouvons au choix copier le fichier /etc/krb5.keytab depuis le serveur ou utiliser Kerberos sur le client pour le faire.
root@debian:~# kadmin -p kdcadmin/admin@STD.LOCAL
Authenticating as principal kdcadmin/admin@STD.LOCAL with password.
Password for kdcadmin/admin@STD.LOCAL: $superKDC$2000
kadmin: ktadd nfs/debian.std.local
Entry for principal nfs/arch.std.local with kvno 3, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/arch.std.local with kvno 3, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
kadmin: exit
Note : si l'on ne redémarre pas l'erreur mount.nfs: Operation not permitted apparaitra lors du montage.
[root@arch ~]# reboot
[root@arch ~]# mkdir /mnt/nfs
[root@arch ~]# mount -t nfs -o sec=krb5p nfs.std.local:/nfs /mnt/nfs/
Note : Ici le partage devrait être accessible depuis l'utilisateur root par contre le message impossible d'ouvrir le répertoire '/mnt/nfs/': Panne d'accès au fichier apparait depuis un simple utilisateur. Il nous faut ici un ticket kerberos.
[user@arch ~]$ kinit nfsuser@STD.LOCAL
Password for nfsuser@STD.LOCAL: NFScher$$
Nous pouvons maintenant avoir accès au partage depuis notre utilisateur.
[user@arch ~]$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: nfsuser@STD.LOCAL
Valid starting Expires Service principal
09/21/2022 18:12:01 09/22/2022 04:12:01 krbtgt/STD.LOCAL@STD.LOCAL
renew until 09/22/2022 18:11:39
09/21/2022 18:12:03 09/22/2022 04:12:01 nfs/nfs.std.local@STD.LOCAL
renew until 09/22/2022 18:11:39
nfs.std.local:/nfs /mnt/nfs nfs defaults,timeo=900,retrans=5,_netdev,sec=krb5p,user,noauto 0 0
root@debian:~# ktadd -k krb5.keytab nfs/archtoi.std.local
root@debian:~# klist
root@debian:~# kdestroy
root@debian:~# kinit -R
root@debian:~# kadmin.local
Authenticating as principal root/admin@STD.LOCAL with password.
kadmin.local: listprincs
K/M@STD.LOCAL
kadmin/admin@STD.LOCAL
kadmin/changepw@STD.LOCAL
kadmin/nfskerb@STD.LOCAL
kdcadmin/admin@STD.LOCAL
kiprop/nfskerb@STD.LOCAL
krbtgt/STD.LOCAL@STD.LOCAL
nfs/arch.std.local@STD.LOCAL
nfs/debian.std.local@STD.LOCAL
nfs/nfs.std.local@STD.LOCAL
nfsuser@STD.LOCAL
root@debian:~# kadmin.local
Authenticating as principal root/admin@STD.LOCAL with password.
kadmin.local: delete_principal nfs/arch.std.local@STD.LOCA
root@debian:~# klist -e -k /etc/krb5.keytab
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
4 nfs/debian.std.local@STD.LOCAL (aes256-cts-hmac-sha1-96)
4 nfs/debian.std.local@STD.LOCAL (aes128-cts-hmac-sha1-96)
root@debian:~# ktutil
ktutil: rkt /etc/krb5.keytab
ktutil: list
slot KVNO Principal
---- ---- ---------------------------------------------------------------------
1 2 nfs/nfs.std.local@STD.LOCAL
2 2 nfs/nfs.std.local@STD.LOCAL
3 2 nfs/arch.std.local@STD.LOCAL
4 2 nfs/arch.std.local@STD.LOCAL
5 2 nfs/debian.std.local@STD.LOCAL
6 2 nfs/debian.std.local@STD.LOCAL
root@debian:~# ktutil
ktutil: delete_entry nfs/arch.std.local@STD.LOCAL
Je vais afficher ici mes règles nftables que j'ai utilisé pour sécuriser mon serveur.
Service | TCP | UDP |
---|---|---|
Kerberos | 88, 749 | 88, 749 |
NFSv4 | 2049 |
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.all.autoconf=0
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.default.autoconf=0
root@debian:~# sysctl -p /etc/sysctl.conf
root@debian:~# systemctl enable nftables.service
#!/usr/sbin/nft -f
flush ruleset
# ----- IPv4 -----
table ip filter {
chain INPUT {
type filter hook input priority 0; policy drop; #by default, we drop traffic
iif lo accept comment "Accept any localhost traffic"
ct state invalid counter drop comment "Drop invalid connections"
ct state { established, related } counter accept comment "Accept traffic originated from us"
iif != lo ip daddr 127.0.0.1/8 counter drop comment "drop connections to loopback not coming from loopback"
tcp flags & (fin | syn | rst | psh | ack | urg) > urg counter drop comment "Drop TCP Null"
tcp flags & (fin | syn | rst | psh | ack | urg) < fin counter drop comment "Drop TCP XMS"
ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem, echo-request } accept comment "Accept ICMP"
iif ens192 ip saddr { 192.168.1.10, 192.168.1.11 } tcp dport { ssh, 88, 749, 2049 } counter accept comment "Accept ssh, kerberos tcp and nfsv4"
iif ens192 ip saddr { 192.168.1.10, 192.168.1.11 } udp dport { 88, 749 } counter accept comment "Accept kerberos udp"
iif ens192 tcp sport { http, https, 53, ntp } counter accept comment "Accept http, https, dns and ntp TCP"
iif ens192 udp sport { 53, ntp } counter accept comment "Accept dns and ntp UDP"
log counter drop #log (/var/log/kern.log), count and drop any other rules
}
chain FORWARD {
type filter hook forward priority 0; policy drop;
counter comment "count dropped packets"
}
chain OUTPUT {
type filter hook output priority 0; policy drop;
oif ens192 ip daddr { 192.168.1.10, 192.168.1.11 } tcp sport { ssh, 88, 749, 2049 } counter accept comment "Accept ssh, kerberos tcp and nfsv4"
oif ens192 ip daddr { 192.168.1.10, 192.168.1.11 } udp sport { 88, 749 } counter accept comment "Accept kerberos udp"
tcp dport { http, https, 53, ntp } counter accept comment "Accept http, https, dns and ntp TCP"
udp dport { 53, ntp } counter accept comment "Accept dns and ntp UDP"
ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem, echo-request, echo-reply } accept comment "Accept ICMP"
log counter drop #log (/var/log/kern.log), count and drop any other rules
}
}
root@debian:~# systemctl restart nftables.service
Contact :