From dd7f092aed90f60fbfe59341fa5a8c4c50d57c69 Mon Sep 17 00:00:00 2001 From: rubenb Date: Wed, 8 May 2024 13:33:10 +0200 Subject: [PATCH] freeradius rol install + config --- .../config-freeradius-totp/handlers/main.yaml | 6 + roles/config-freeradius-totp/tasks/main.yaml | 131 ++++++++++++++++++ .../templates/clients.j2 | 4 + .../templates/default.j2 | 47 +++++++ .../templates/dictionary.j2 | 1 + .../templates/filter.j2 | 103 ++++++++++++++ .../templates/freeradiusservice.j2 | 71 ++++++++++ .../config-freeradius-totp/templates/ldap.j2 | 60 ++++++++ .../templates/radiusd.j2 | 63 +++++++++ .../templates/radiusdpam.j2 | 11 ++ roles/config-freeradius-totp/vars/main.yaml | 29 ++++ 11 files changed, 526 insertions(+) create mode 100644 roles/config-freeradius-totp/handlers/main.yaml create mode 100644 roles/config-freeradius-totp/tasks/main.yaml create mode 100644 roles/config-freeradius-totp/templates/clients.j2 create mode 100644 roles/config-freeradius-totp/templates/default.j2 create mode 100644 roles/config-freeradius-totp/templates/dictionary.j2 create mode 100644 roles/config-freeradius-totp/templates/filter.j2 create mode 100644 roles/config-freeradius-totp/templates/freeradiusservice.j2 create mode 100644 roles/config-freeradius-totp/templates/ldap.j2 create mode 100644 roles/config-freeradius-totp/templates/radiusd.j2 create mode 100644 roles/config-freeradius-totp/templates/radiusdpam.j2 create mode 100644 roles/config-freeradius-totp/vars/main.yaml diff --git a/roles/config-freeradius-totp/handlers/main.yaml b/roles/config-freeradius-totp/handlers/main.yaml new file mode 100644 index 0000000..b46b437 --- /dev/null +++ b/roles/config-freeradius-totp/handlers/main.yaml @@ -0,0 +1,6 @@ +# restart freeradius service to apply changes +- name: restart freeradius + service: + name: "{{ freeradius_daemon }}" + state: restarted + enabled: yes \ No newline at end of file diff --git a/roles/config-freeradius-totp/tasks/main.yaml b/roles/config-freeradius-totp/tasks/main.yaml new file mode 100644 index 0000000..f62722c --- /dev/null +++ b/roles/config-freeradius-totp/tasks/main.yaml @@ -0,0 +1,131 @@ +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# Install and configure FREERADIUS TOTP +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# install packages if there are not present in the system +- name: install freeradius packages if is not in the system + apt: + name: "{{ item }}" + state: present + with_items: + - freeradius + - freeradius-ldap + - libpam-google-authenticator +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# config symbolic files to enable modules +- name: create a symbolic link + ansible.builtin.file: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: freerad + group: freerad + state: link + loop: + - { src: '"{{ freeradius_mods_available_folder }}"ldap', dest: '"{{ freeradius_mods_enabled_folder }}"ldap' } + - { src: '"{{ freeradius_mods_available_folder }}"pam', dest: '"{{ freeradius_mods_enabled_folder }}"pam' } +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# config default file /etc/freeradius/3.0/sites-enabled/default +- name: config default file + ansible.builtin.template: + src: default.j2 + dest: "{{ freeradius_default_config }}" + owner: freerad + group: freerad + mode: '0640' + backup: yes +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# config default file /etc/freeradius/3.0/mods-available/ldap +- name: config ldap file + ansible.builtin.template: + src: ldap.j2 + dest: "{{ freeradius_mod_ldap }}" + owner: freerad + group: freerad + mode: '0640' + backup: yes +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# config default file /etc/freeradius/3.0/dictionary +- name: config dictionary file + ansible.builtin.template: + src: dictionary.j2 + dest: "{{ freeradius_dictionary_config }}" + owner: freerad + group: freerad + mode: '0640' + backup: yes +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# config default file /etc/freeradius/3.0/clients.conf +- name: config clients.conf file + ansible.builtin.template: + src: clients.j2 + dest: "{{ freeradius_clients_config }}" + owner: freerad + group: freerad + mode: '0640' + backup: yes +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# config default file /etc/freeradius/3.0/policy.d/filter +- name: config filter file + ansible.builtin.template: + src: filter.j2 + dest: "{{ freeradius_filter_config }}" + owner: freerad + group: freerad + mode: '0640' + backup: yes +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# config default file /etc/freeradius/3.0/radiusd.conf +- name: config radius.conf file + ansible.builtin.template: + src: radiusd.j2 + dest: "{{ freeradius_base_config }}" + owner: freerad + group: freerad + mode: '0640' + backup: yes +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# config default file /etc/pam.d/radiusd +- name: config pam radiusd file + ansible.builtin.template: + src: radiusdpam.j2 + dest: "{{ freeradius_pam_config }}" + owner: root + group: root + mode: '0644' +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# config default file /lib/systemd/system/freeradius.service +- name: config freeradius systemd service file + ansible.builtin.template: + src: freeradiusservice.j2 + dest: "{{ freeradius_service_config }}" + owner: root + group: root + mode: '0644' +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# force systemd to reread configs +- name: Just force systemd to reread configs (2.4 and above) + ansible.builtin.systemd_service: + daemon_reload: true + notify: restart freeradius +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \ No newline at end of file diff --git a/roles/config-freeradius-totp/templates/clients.j2 b/roles/config-freeradius-totp/templates/clients.j2 new file mode 100644 index 0000000..87ec429 --- /dev/null +++ b/roles/config-freeradius-totp/templates/clients.j2 @@ -0,0 +1,4 @@ +client opnsense { + ipaddr = 0.0.0.0/0 + secret = "{{ bindradiusclient_password }}" +} \ No newline at end of file diff --git a/roles/config-freeradius-totp/templates/default.j2 b/roles/config-freeradius-totp/templates/default.j2 new file mode 100644 index 0000000..050b4fa --- /dev/null +++ b/roles/config-freeradius-totp/templates/default.j2 @@ -0,0 +1,47 @@ +server default { +listen { + type = auth + ipaddr = * + port = 0 + limit { + max_connections = 16 + lifetime = 0 + idle_timeout = 30 + } +} +listen { + ipaddr = * + port = 0 + type = acct + limit { + } +} +authorize { + filter_username + filter_google_totp + ldap + if (&Google-Password) { + update control { + &User-Password := "%{&Google-Password}" + Auth-Type := PAP + } + } +} +authenticate { + Auth-Type PAP { + pap + if (&Google-Password) { + update request { + &User-Password := "%{&Google-Password}" + } + pam + } else { + update reply { + Reply-Message := "Login incorrect: TOTP Fail" + } + reject + } + } + pam +} +} diff --git a/roles/config-freeradius-totp/templates/dictionary.j2 b/roles/config-freeradius-totp/templates/dictionary.j2 new file mode 100644 index 0000000..a4c64b5 --- /dev/null +++ b/roles/config-freeradius-totp/templates/dictionary.j2 @@ -0,0 +1 @@ +ATTRIBUTE Google-Password 3000 string \ No newline at end of file diff --git a/roles/config-freeradius-totp/templates/filter.j2 b/roles/config-freeradius-totp/templates/filter.j2 new file mode 100644 index 0000000..66f98ff --- /dev/null +++ b/roles/config-freeradius-totp/templates/filter.j2 @@ -0,0 +1,103 @@ +deny_realms { + if (&User-Name && (&User-Name =~ /@|\\/)) { + reject + } +} +filter_username { + if (&User-Name) { + if (&User-Name =~ / /) { + update request { + &Module-Failure-Message += 'Rejected: User-Name contains whitespace' + } + reject + } + if (&User-Name =~ /@[^@]*@/ ) { + update request { + &Module-Failure-Message += 'Rejected: Multiple @ in User-Name' + } + reject + } + if (&User-Name =~ /\.\./ ) { + update request { + &Module-Failure-Message += 'Rejected: User-Name contains multiple ..s' + } + reject + } + if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/)) { + update request { + &Module-Failure-Message += 'Rejected: Realm does not have at least one dot separator' + } + reject + } + if (&User-Name =~ /\.$/) { + update request { + &Module-Failure-Message += 'Rejected: Realm ends with a dot' + } + reject + } + if (&User-Name =~ /@\./) { + update request { + &Module-Failure-Message += 'Rejected: Realm begins with a dot' + } + reject + } + } +} +filter_password { + if (&User-Password && \ + (&User-Password != "%{string:User-Password}")) { + update request { + &Tmp-String-0 := "%{string:User-Password}" + &User-Password := "%{string:Tmp-String-0}" + &Tmp-String-0 !* "" + } + } +} +filter_inner_identity { + if (!&outer.request:User-Name || !&User-Name) { + update request { + Module-Failure-Message = "User-Name is required for tunneled authentication" + } + reject + } + if (&outer.request:User-Name != &User-Name) { + if (&outer.request:User-Name =~ /@([^@]+)$/) { + update request { + Outer-Realm-Name = "%{1}" + } + if (&outer.request:User-Name !~ /^(anon|@)/) { + update request { + Module-Failure-Message = "User-Name is not anonymized" + } + reject + } + } + elsif (&outer.request:User-Name !~ /^anon/) { + update request { + Module-Failure-Message = "User-Name is not anonymized" + } + reject + } + if (&User-Name =~ /@([^@]+)$/) { + update request { + Inner-Realm-Name = "%{1}" + } + if (&Outer-Realm-Name && \ + (&Inner-Realm-Name != &Outer-Realm-Name) && \ + (&Inner-Realm-Name !~ /\.%{Outer-Realm-Name}$/)) { + update request { + Module-Failure-Message = "Inner realm '%{Inner-Realm-Name}' and outer realm '%{Outer-Realm-Name}' are not from the same domain." + } + reject + } + } + } +} +filter_google_totp { + if (&User-Password =~ /^(.*)([0-9]{6})$/) { + update request { + &User-Password := "%{1}" + &Google-Password := "%{2}" + } + } +} \ No newline at end of file diff --git a/roles/config-freeradius-totp/templates/freeradiusservice.j2 b/roles/config-freeradius-totp/templates/freeradiusservice.j2 new file mode 100644 index 0000000..efa885c --- /dev/null +++ b/roles/config-freeradius-totp/templates/freeradiusservice.j2 @@ -0,0 +1,71 @@ +[Unit] +Description=FreeRADIUS multi-protocol policy server +After=network-online.target +Documentation=man:radiusd(8) man:radiusd.conf(5) http://wiki.freeradius.org/ http://networkradius.com/doc/ + +[Service] +Type=notify +WatchdogSec=60 +NotifyAccess=all +EnvironmentFile=-/etc/default/freeradius + +# FreeRADIUS can do static evaluation of policy language rules based +# on environmental variables which is very useful for doing per-host +# customization. +# Unfortunately systemd does not allow variable substitutions such +# as %H or $(hostname) in the EnvironmentFile. +# We provide HOSTNAME here for convenience. +Environment=HOSTNAME=%H + +# Limit memory to 2G this is fine for %99.99 of deployments. FreeRADIUS +# is not memory hungry, if it's using more than this, then there's probably +# a leak somewhere. +MemoryLimit=2G + +# Ensure the daemon can still write its pidfile after it drops +# privileges. Combination of options that work on a variety of +# systems. Test very carefully if you alter these lines. +RuntimeDirectory=freeradius +RuntimeDirectoryMode=0775 +#User=freerad +#Group=freerad +User=root +Group=root + +ExecStartPre=/usr/sbin/freeradius $FREERADIUS_OPTIONS -Cx -lstdout +ExecStart=/usr/sbin/freeradius -f $FREERADIUS_OPTIONS +Restart=on-failure +RestartSec=5 +ExecReload=/usr/sbin/freeradius $FREERADIUS_OPTIONS -Cxm -lstdout +ExecReload=/bin/kill -HUP $MAINPID + +# Don't elevate privileges after starting +NoNewPrivileges=true + +# Allow binding to secure ports, broadcast addresses, and raw interfaces. +#AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_CHOWN CAP_DAC_OVERRIDE + +# Private /tmp that isn't shared by other processes +PrivateTmp=true + +# cgroups are readable only by radiusd, and child processes +ProtectControlGroups=true + +# don't load new kernel modules +ProtectKernelModules=true + +# don't tune kernel parameters +ProtectKernelTunables=true + +# Only allow native system calls +SystemCallArchitectures=native + +# We shouldn't be writing to the configuration directory +ReadOnlyDirectories=/etc/freeradius/ + +# We can read and write to the log directory. +ReadWriteDirectories=/var/log/freeradius/ + + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/config-freeradius-totp/templates/ldap.j2 b/roles/config-freeradius-totp/templates/ldap.j2 new file mode 100644 index 0000000..745008b --- /dev/null +++ b/roles/config-freeradius-totp/templates/ldap.j2 @@ -0,0 +1,60 @@ +ldap { + server = 'ldap.verdnatura.es' + identity = 'cn=admin,dc=verdnatura,dc=es' + password = "{{ bindradiusldap_password }}" + base_dn = 'dc=verdnatura,dc=es' + user_dn = "LDAP-UserDn" + update { + control:Password-With-Header += 'userPassword' + control:NT-Password := 'sambaNTPassword' + } + user { + base_dn = "ou=users,${..base_dn}" + filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})" + } + group { + base_dn = "ou=groups,${..base_dn}" + name_attribute = 'cn' + membership_attribute = 'memberUid' + membership_filter = "(memberUid=%{%{Stripped-User-Name}:-%{User-Name}})" + filter = '(objectClass=posixGroup)' + cacheable_name = yes + } + accounting { + reference = "%{tolower:type.%{Acct-Status-Type}}" + type { + start { + update {description := "Online at %S"} + } + interim-update { + update {description := "Last seen at %S"} + } + stop { + update {description := "Offline at %S"} + } + } + } + post-auth { + update {description := "Authenticated at %S"} + } + options { + rebind = yes + res_timeout = 10 + srv_timelimit = 3 + net_timeout = 1 + idle = 60 + probes = 3 + interval = 3 + ldap_debug = 0x0028 + } + pool { + start = ${thread[pool].start_servers} + min = ${thread[pool].min_spare_servers} + max = ${thread[pool].max_servers} + spare = ${thread[pool].max_spare_servers} + uses = 0 + retry_delay = 30 + lifetime = 0 + idle_timeout = 60 + } +} diff --git a/roles/config-freeradius-totp/templates/radiusd.j2 b/roles/config-freeradius-totp/templates/radiusd.j2 new file mode 100644 index 0000000..b889595 --- /dev/null +++ b/roles/config-freeradius-totp/templates/radiusd.j2 @@ -0,0 +1,63 @@ +prefix = /usr +exec_prefix = /usr +sysconfdir = /etc +localstatedir = /var +sbindir = ${exec_prefix}/sbin +logdir = /var/log/freeradius +raddbdir = /etc/freeradius/3.0 +radacctdir = ${logdir}/radacct +name = freeradius +confdir = ${raddbdir} +modconfdir = ${confdir}/mods-config +certdir = ${confdir}/certs +cadir = ${confdir}/certs +run_dir = ${localstatedir}/run/${name} +db_dir = ${raddbdir} +libdir = /usr/lib/freeradius +pidfile = ${run_dir}/${name}.pid +max_request_time = 30 +cleanup_delay = 5 +max_requests = 16384 +hostname_lookups = no +log { + destination = files + colourise = yes + file = ${logdir}/radius.log + syslog_facility = daemon + stripped_names = no + auth = yes + auth_badpass = no + auth_goodpass = no + msg_denied = "You are already logged in - access denied" +} +checkrad = ${sbindir}/checkrad +ENV { +} +security { + user = root + group = root + allow_core_dumps = no + max_attributes = 200 + reject_delay = 1 + status_server = yes +} +proxy_requests = yes +$INCLUDE proxy.conf +$INCLUDE clients.conf +thread pool { + start_servers = 5 + max_servers = 32 + min_spare_servers = 3 + max_spare_servers = 10 + max_requests_per_server = 0 + auto_limit_acct = no +} +modules { + $INCLUDE mods-enabled/ +} +instantiate { +} +policy { + $INCLUDE policy.d/ +} +$INCLUDE sites-enabled/ \ No newline at end of file diff --git a/roles/config-freeradius-totp/templates/radiusdpam.j2 b/roles/config-freeradius-totp/templates/radiusdpam.j2 new file mode 100644 index 0000000..bb2f84a --- /dev/null +++ b/roles/config-freeradius-totp/templates/radiusdpam.j2 @@ -0,0 +1,11 @@ +# +# /etc/pam.d/radiusd - PAM configuration for FreeRADIUS +# + +# We fall back to the system default in /etc/pam.d/common-* +# +auth required pam_google_authenticator.so forward_pass +#@include common-auth +#@include common-account +#@include common-password +#@include common-session \ No newline at end of file diff --git a/roles/config-freeradius-totp/vars/main.yaml b/roles/config-freeradius-totp/vars/main.yaml new file mode 100644 index 0000000..8315309 --- /dev/null +++ b/roles/config-freeradius-totp/vars/main.yaml @@ -0,0 +1,29 @@ +--- +# vars file +freeradius_base_folder: /etc/freeradius/3.0/ +freeradius_mods_available_folder: '"{{ freeradius_base_folder }}"mods-available/' +freeradius_mods_enabled_folder: '"{{ freeradius_base_folder }}"mods-enabled/' +freeradius_sites_available_folder: '"{{ freeradius_base_folder }}"sites-available/' +freeradius_base_config: '"{{ freeradius_base_folder }}"radiusd.conf' +freeradius_default_config: '"{{ freeradius_sites_available_folder }}"default' +freeradius_dictionary_config: '"{{ freeradius_base_folder }}"dictionary' +freeradius_clients_config: '"{{ freeradius_base_folder }}"clients.conf' +freeradius_mod_ldap: '"{{ freeradius_mods_available_folder }}"ldap' +freeradius_filter_config: '"{{ freeradius_base_folder }}"policy.d/filter' +freeradius_daemon: freeradius +bindradiusldap_password: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 66633833303261326432393637656134323532346134333361326333343737633662383935663761 + 3737336530626166373035666632663338343331396162350a646337376435346534323131386136 + 30333834643532656632366139343436663565326635303037326537633135323935393830373064 + 3361393262623030620a353333353337643836636534366334646565633332393633626362626134 + 31633237373761666637333364383435663633383363373134393432653136663235 +bindradiusclient_password: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 62356138356239653862643333303865323030383461396235356231653738343537366363636538 + 3062303464396239313832613965336333343033356430660a663031653434393234666530613632 + 31656339623365353236303130663732323138636335356562376562306430326231303662336339 + 3732373766646663380a343430306437393436313163383162313532626138623235356132663035 + 36303837353661643130323635343263303661376566306438373364386539623535 +freeradius_pam_config: /etc/pam.d/radiusd +freeradius_service_config: /lib/systemd/system/freeradius.service \ No newline at end of file