summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Chudnick <sam@chudnick.com>2022-12-08 20:44:37 -0500
committerSam Chudnick <sam@chudnick.com>2022-12-08 20:44:37 -0500
commit3fb2b9563d9b58a9683808c6620832dc71f76b20 (patch)
tree9c208db70957ba26fbcc2d87f3b91df7117617c8
Initial commit
-rw-r--r--.swobin0 -> 12288 bytes
-rw-r--r--.swpbin0 -> 12288 bytes
-rw-r--r--about-me.html18
-rw-r--r--articles/freeipa-server.html176
-rw-r--r--articles/icinga-agent.html135
-rw-r--r--articles/icinga-director.html112
-rw-r--r--articles/icinga-influx.html133
-rw-r--r--articles/icinga-master.html276
-rw-r--r--articles/luks.html132
-rw-r--r--articles/mail-server.html723
-rw-r--r--articles/mdadm-raid.html120
-rw-r--r--articles/mutt.html27
-rw-r--r--articles/pam-tfa.html157
-rw-r--r--articles/template.html27
-rw-r--r--blog.html19
-rw-r--r--donate.html22
-rw-r--r--images/bitcoin.pngbin0 -> 988 bytes
-rw-r--r--images/desktop-720.pngbin0 -> 781999 bytes
-rw-r--r--images/desktop.pngbin0 -> 1079036 bytes
-rw-r--r--images/director/debian-template.pngbin0 -> 22764 bytes
-rw-r--r--images/director/director.pngbin0 -> 85761 bytes
-rw-r--r--images/director/host-services.pngbin0 -> 22718 bytes
-rw-r--r--images/director/hosttemplate.pngbin0 -> 63328 bytes
-rw-r--r--images/director/linux-template.pngbin0 -> 18129 bytes
-rw-r--r--images/director/service-set.pngbin0 -> 20965 bytes
-rw-r--r--images/director/service-template.pngbin0 -> 34832 bytes
-rw-r--r--images/director/templates.pngbin0 -> 5095 bytes
-rw-r--r--images/freeipa-webui.pngbin0 -> 78181 bytes
-rw-r--r--images/git.svg15
-rw-r--r--images/icinga-login.pngbin0 -> 233089 bytes
-rw-r--r--images/raid/fdisk.pngbin0 -> 392139 bytes
-rw-r--r--images/raid/lsblk.pngbin0 -> 49073 bytes
-rw-r--r--images/rss.svg33
-rw-r--r--index.html31
-rw-r--r--kb.html82
-rw-r--r--projects.html22
-rw-r--r--projects/mfa.html150
-rw-r--r--projects/template.html107
-rw-r--r--rss.xml2020
-rw-r--r--software.html57
-rw-r--r--style.css173
-rw-r--r--template.html18
42 files changed, 4785 insertions, 0 deletions
diff --git a/.swo b/.swo
new file mode 100644
index 0000000..7a6aeff
--- /dev/null
+++ b/.swo
Binary files differ
diff --git a/.swp b/.swp
new file mode 100644
index 0000000..7fc4c38
--- /dev/null
+++ b/.swp
Binary files differ
diff --git a/about-me.html b/about-me.html
new file mode 100644
index 0000000..afac43f
--- /dev/null
+++ b/about-me.html
@@ -0,0 +1,18 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title>chudnick.com - About Me</title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' type='text/css' href='style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1 class=pagetop>About Me</h1></header>
12 <main>
13 A page for biographical information.
14 </main>
15 <footer><a href=index.html>www.chudnick.com</a></footer>
16</body>
17</html>
18
diff --git a/articles/freeipa-server.html b/articles/freeipa-server.html
new file mode 100644
index 0000000..80825d0
--- /dev/null
+++ b/articles/freeipa-server.html
@@ -0,0 +1,176 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' href='../style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1>FreeIPA Server Setup</h1></header>
12 <main>
13 <p>FreeIPA is a centralized idenity management solution developed
14 by Redhat. It is in my opinion the most functional libre alternative
15 to Microsoft's Active Directory. Like AD, FreeIPA integrates all of
16 the pieces needed to setup a domain including LDAP, Kerberos,
17 a Certificate Authority, and much more.</p>
18
19 <p>I will be using Fedora 35 in this tutorial. As of Debian 11, the
20 FreeIPA server is still not in the Debian repos. You will need either
21 a Fedora or a RHEL machine. A CentOS fork may work also but I have not
22 tested that.</p>
23
24 <h2>FreeIPA in an Enterprise</h2>
25
26 <p>For readers exploring the use of FreeIPA in a business
27 environment, note that FreeIPA documentation explicitly states that
28 it is not a replacement for Active Directory. I have not personally
29 tried to join a Windows computer to a FreeIPA domain, and so I can't
30 speak to how well that would work. FreeIPA would also not be able to push
31 out policy to Windows machines as is done with Group Policy. FreeIPA
32 is though able to create inter-domain trusts with an existing AD
33 infrastructure.</p>
34
35 <h2>The Case for FreeIPA at Home</h2>
36 <p>Using a full Kerberos and LDAP identity management server may
37 seem like overkill at home. And if you only have a single computer
38 then it probably is. But scaling up even slightly, to perhaps a small
39 family each with their own computer, will make having FreeIPA
40 advantageous (<em>your family is all using Linux, right?</em>). This
41 will be especially apparent if you are hosting your own services.
42 If you are for instance hosting a Jellyfin media server that everyone
43 in your family accesses, you won't want them to juggle separate
44 passwords for Jellyfin when you could just have them use the same
45 password they do on the computer. This single/same sign-on capability is
46 one of the most practically useful aspects of FreeIPA.</p>
47
48 <h2>Install Packages</h2>
49 <p>We start as usual by installing the required packages.</p>
50
51 <pre><code>dnf install freeipa-server freeipa-dns</code></pre>
52
53 <h2>Set Hostname</h2>
54 <p>The server will need to have a fully qualified hostname
55 before setting up IPA. You will need both a hostname for the server
56 itself and the domain name you will want for the FreeIPA domain. I
57 will be using <em>ipaserver.myhome.local</em>, where
58 <em>ipaserver</em> is the hostname and <em>myhome.local</em> is the
59 domain name.</p>
60
61 <pre><code>hostnamectl set-hostname <em>ipaserver.home.local</em></code></pre>
62
63 <p>We'll also need to add a hosts file entry to
64 <strong>/etc/hosts</strong>. Open that file in an editor and add a new
65 line with the IP of the server, the fully qualified name, and the
66 hostname.</p>
67
68 <pre><code>192.168.1.10 ipaserver.myhome.local ipaserver</code></pre>
69
70
71 <p>Make sure to reboot the server before continuing to complete
72 the hostname change.</p>
73
74 <h2>Firewall Configuration</h2>
75 <p>We'll need to allow several ports for FreeIPA to function properly.
76 Fedora 35 uses firewalld by default but I am going to disable that
77 in favor of UFW here.</p>
78
79 <pre><code><em>#Install UFW</em>
80dnf install ufw
81<em># Stop and disable firewalld</em>
82systemctl disable --now firewalld
83<em># Configure UFW</em>
84ufw enable
85ufw allow ssh
86ufw allow dns
87ufw allow 88 comment kerberos
88ufw allow 389 comment ldap
89ufw allow 443 comment webui
90ufw allow 636 comment ldaps
91ufw default deny incoming
92ufw reload</code></pre>
93
94 <h2>Configure FreeIPA</h2>
95 <p>Now we can run the FreeIPA setup script. This is an interactive but mostly
96 automatic process that will configure all of the IPA components. The
97 <strong>--mkhomedir</strong> flag will configure the server to create home
98 directories for IPA users on their first login and would otherwise have to be
99 done manually.</p>
100
101 <pre><code>ipa-server-install --mkhomedir</code></pre>
102
103 <p>That command will bring you into the install script. You will be prompted
104 several times before the bulk of the configuration happens. Default values
105 are show in brackets after the prompt. Let's run through those prompts.<br><br>
106 <strong>Do you want to configure integrated DNS (BIND)?</strong>:
107 <em>yes</em><br><br>
108 <strong>Sever host name</strong>: the default value should be showing
109 <em>ipaserver.myhome.local</em> which is what we want. Simply hit enter to acecpt
110 the default.<br><br>
111 <strong>Please confirm the domain name</strong>: The default here should be
112 correct <em>myhome.local</em> so hit enter to accept that.<br><br>
113 <strong>Please provide a realm name</strong>: This should just be the domain
114 name in all uppercase. If the default looks correct just hit enter.<br><br>
115 <strong>Directory Manager password</strong>: This is the password for an
116 administrator account used by system services. You will not need this for daily
117 use so I recommend setting it to a long randomly generated string. I have found
118 myself that using an extremely long password here will cause the installation to
119 fail. A password under 40 characters should be safe.<br><br>
120 <strong>IPA admin password</strong>: This is the password for your initial admin
121 user. Make this a strong password as this user has full admin rights for the
122 entire domain.<br><br>
123 <strong>Do you want to configure DNS forwarders</strong>: This allows you to
124 configure the IPA server to forward DNS requests to another DNS server for
125 zones it is not authoratitve for. The DNS server is configured by default as
126 a recursive DNS server so answering no does not prevent internet access. If you
127 have another DNS server that should be used instead then answer yes and provide
128 the IP address when prompted.<br><br>
129
130 <strong>Do you want to configure chrony with NTP server or pool address?</strong>
131 : Here you can configure a custom NTP server or pool for the NTP daemon chrony.
132 If you already have an NTP server on your network answer yes and provide its IP.
133 If you want to leave the deafult chrony configuration then answer no. Time
134 synchronization is very important in Kerberos so you should consider how you
135 want to achieve that on your network. If you do not have an NTP server you may
136 want to configure the IPA server as one later.<br><br>
137
138 <strong>Continue to configure the system with these values?</strong>: This is a
139 final confirmation before the script takes over and configures the IPA
140 components. Review the information printed and enter yes if it all looks correct.
141 </p>
142
143 <p>The install script will now run through configuration. This process usually
144 takes several minutes. When finished you should get a message saying
145 <strong>The ipa-server-install command was successful</strong>.</p>
146
147 <p>To finish, run this command to receive a Kerberos TGT. Provide the
148 password for the admin user when prompted.</p>
149
150 <pre><code>kinit admin</code></pre>
151
152 <h2>Accessing the Web Interface</h2>
153
154 <p>You are now able to manage FreeIPA through the web interface. You can
155 browse either to the IP or the hostname if your DNS is configured correctly.
156 You should see a screen similar to this.</p>
157
158 <img alt="FreeIPA Login Screen" src=../images/freeipa-webui.png>
159
160 <p>Login with the username admin and the password you set during the
161 insallation. You are now ready to begin configuring your IPA domain.</p>
162 </main>
163<p>
164<hr>
165Consider <a href=../donate.html>donating</a> if this article was useful.
166<a class=qr href=../images/bitcoin.png>[BTC]</a>
167</p>
168 </main>
169 <footer>
170 <a href=../kb.html>Knowledge Base</a>
171 <br>
172 <a href=../index.html>www.chudnick.com</a>
173 </footer>
174</body>
175</html>
176
diff --git a/articles/icinga-agent.html b/articles/icinga-agent.html
new file mode 100644
index 0000000..e0aa6c0
--- /dev/null
+++ b/articles/icinga-agent.html
@@ -0,0 +1,135 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' href='../style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1>Icinga Agent Node Installation and Configuration</h1></header>
12 <main>
13 <p>With the Icinga master node configured, the servers we want
14 to monitor can now be added as agent nodes. As the names suggest,
15 the Icinga master node pushes the desired configuration to agent
16 nodes, while agent nodes report the configured status checks back
17 to the master. Communication between the master and agent nodes is
18 encrypted via TLS, with the master node acting as a certificate
19 authority.</p>
20
21 <p>You can find my script to automate this process
22 <a href=https://git.chudnick.com/server-scripts/tree/monitoring/icinga-agent>
23 here</a>.</p>
24
25 <h2>Install Pakcages</h2>
26 <p>Start by installing the required packages on the server to be
27 monitored.</p>
28
29 <pre><code>apt install icinga2 monitoring-plugins
30monitoring-plugins-contrib</code></pre>
31
32 <h2>Initialize PKI with master</h2>
33 <p>Now we need to setup the PKI that will be used for the communication
34 with the master node. The first step is to generate a certificate
35 signing request. Replace <em>hostname</em> with the FQDN of the server.</p>
36
37 <pre><code>icinga2 pki new-cert --cn "<em>hostname</em>" --cert "/etc/icinga2/pki/<em>hostname</em>.crt" --csr "/etc/icinga2/pki/<em>hostname</em>.csr" --key "/etc/icinga2/pki/<em>hostname</em>.key"</code></pre>
38
39 <p>Next we save the master node's public key certificate. Replace
40 <em>master</em> with the FQDN of your master node.</p>
41
42 <pre><code>icinga2 pki save-cert --host "<em>master</em>" --port 5665 --key "/etc/icinga2/pki/<em>hostname</em>.key" --trustedcert "/etc/icinga2/pki/trusted-master.crt"</code></pre>
43
44 <p>Receive signed certificate from the master node.</p>
45
46 <pre><code>icinga2 pki request --host "<em>master</em>" --port 5665 --key "/etc/icinga2/pki/<em>hostname</em>.key" --cert "/etc/icinga2/pki/<em>hostname</em>.crt" --trustedcert "/etc/icinga2/pki/trusted-master.crt" --ca "/etc/icinga2/pki/ca.crt"</code></pre>
47
48 <h2>Deploy configuration files</h2>
49 <p>Write Icinga configuration.</p>
50
51 <pre><code><strong>/etc/icinga2/icinga2.conf</strong>
52include "constants.conf"
53const NodeName = "$nodename"
54include "zones.conf"
55include "features-enabled/*.conf"
56include &lt;itl&gt;
57include &lt;plugins&gt;
58include &lt;plugins-contrib&gt;
59include &lt;manubulon&gt;
60include &lt;windows-plugins&gt;
61include &lt;nscp&gt;"</code></pre>
62
63 <p>Write zones configuration.</p>
64
65 <pre><code><strong>/etc/icinga2/zones.conf</strong>
66echo "object Endpoint "<em>hostname</em>" {}
67object Zone "<em>hostname</em>" {
68 parent = "<em>master</em>"
69 endpoints = [ "<em>hostname</em>" ]
70}
71object Zone "<em>master</em>" {
72 endpoints = [ "<em>master</em>" ]
73}
74object Endpoint "<em>master</em>" {
75 host = "<em>master</em>"
76}
77object Zone "director-global" {
78 global = true
79}</code></pre>
80
81 <p>Write API configuration file.</p>
82
83 <pre><code><strong>/etc/icinga2/features-available/api.conf</strong>
84echo "object ApiListener \"api\" {
85 accept_commands = true
86 accept_config = true
87}</code></pre>
88
89 <h2>Enable API</h2>
90 <p>Next, we need to enable the API on the agent.</p>
91
92 <pre><code>icinga2 feature enable api
93
94mkdir -p /var/lib/icinga2/certs
95
96cp /etc/icinga2/pki/<em>hostname</em>.crt /etc/icinga2/pki/<em>hostname</em>.key /etc/icinga2/pki/ca.crt /var/lib/icinga2/certs/
97
98chown -R nagios: /var/lib/icinga2/certs/</code></pre>
99
100 <h2>Sign agent CSR on Master</h2>
101 <p>The only action needed on the master node is to sign the agent's
102 CSR. Logon to your master node and run the following:</p>
103
104 <pre><code>fpr="$(icinga2 ca list | tail -1 | cut -d '|' -f 1)"
105icinga2 ca sign $fpr</code></pre>
106
107 <h2>Configure Firewall</h2>
108 <p>Before finishing we need to open the proper firewall port.
109 I will use UFW in the example here and allow traffic only only
110 from the master node for best security.</p>
111
112 <pre><code>ufw allow proto tcp from <em>master-ip</em> to any port 5665</code></pre>
113
114 <h2>Restart Icinga on Agent</h2>
115 <p>Finally, restart the icinga service on the agent node.</p>
116
117 <pre><code>systemctl restart icinga2</code></pre>
118
119 <p>The Icinga agent node will now pull down configuration from the master.
120 You will know that this worked if <em>/var/lib/icinga2/api/zones</em>
121 begins to populate with new files.</p>
122<p>
123<hr>
124Consider <a href=../donate.html>donating</a> if this article was useful.
125<a class=qr href=../images/bitcoin.png>[BTC]</a>
126</p>
127 </main>
128 <footer>
129 <a href=../kb.html>Knowledge Base</a>
130 <br>
131 <a href=../index.html>www.chudnick.com</a>
132 </footer>
133</body>
134</html>
135
diff --git a/articles/icinga-director.html b/articles/icinga-director.html
new file mode 100644
index 0000000..3993949
--- /dev/null
+++ b/articles/icinga-director.html
@@ -0,0 +1,112 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' href='../style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1>Icinga Director</h1></header>
12 <main>
13 <p>Icinga Director is the web-based configuration tool for Icinga2.
14 Director provides a simple interface for configuring the various parts
15 of your monitoring environment. Even if you would rather do all of
16 the configuration from a terminal, I still recommend using Director for
17 its self-service API which allows new nodes to register with no interaction
18 required on the node (i.e. via a script).</p>
19
20 <p>Start by logging into your Icinga instance. If you followed the
21 <a href=icinga2-master.html>master installation guide</a> you should have
22 a tab labeled <strong>Icinga Director</strong>. Click on that, and you should
23 see something similar to this:</p>
24 <img src=../images/director/director.png>
25
26 <h2>Hosts</h2>
27 <p>Let's start by looking at the hosts section. Clicking on the hosts
28 button from the Director menu will present you with several options.
29 Click on host templates, and then click add to define our first host
30 template. Host templates are the building blocks of Icinga, they allow
31 for your nodes to be structured however you see fit, and then to have
32 monitoring checks automatically applied to them based on that structure.</p>
33 <p>I like to structure my host templates by operating system. For example,
34 I have a template called <strong>Linux Server</strong>, which is designed
35 to encompass all of the Linux servers in my environment. I then get more
36 specific, creating templates based on distro. These templates are children
37 of the Linux Server template, so they inherit whatever is applied to the
38 parent, but then can have distro-specific checks applied to themselves.</p>
39 <p>Start by giving your template a name - I will use <strong>Linux Server
40 </strong> here. Groups can be left empty for now, but you may want to
41 add groups and apply them to templates later. The check command should
42 be set to hostalive. Expand <strong>Icinga Agent and zone settings</strong>
43 and set <em>Icinga2 Agent</em>, <em>Establish connection</em>,
44 and <em>Accepts config</em> to Yes. Click store to save the template.
45 Your template should look like this:</p>
46
47 <img src=../images/director/hosttemplate.png>
48
49 <h2>Service templates</h2>
50 <p>Let's turn to services now. Return to the Director menu and select
51 Services. The services menu is structured similar to hosts, and we will
52 start with the service templates section. The idea behind service templates
53 is very similar to host templates. Typically, a service template corresponds
54 to a single monitoring command.</p>
55 <p>As an example, we'll create a service template for a monitoring
56 command that checks the status of a web server. Give the template a
57 name, set the check command to http, and finally expand <strong>Icinga
58 Agent and zone settings</strong> and set <strong>Run on agent
59 </strong> to no. We set this to no because we want Icinga to query
60 the web server externally instead of from the web server itself.</p>
61
62 <img src=../images/director/service-template.png>
63
64 <h2>Service sets</h2>
65 <p>Service sets are simply groups of service templates. They can be
66 structured however you see fit. Service sets can then be applied to
67 hosts/host templates to have the checks be automatically applied.</p>
68
69 <p>Add a new service set and give it a name. Then click on the services
70 tab and add all of the services you want to group into that set.
71 Here is an example of a service set <strong>Linux Standard</strong>
72 that has service checks that should be applied to all Linux servers.</p>
73
74 <img src=../images/director/service-set.png>
75
76 <p>To bring service sets and host templates together, return to your host
77 templates, select Linux Server, select the services tab, and then select
78 add service set and choose your desired set from the dropdown menu.</p>
79
80 <img src=../images/director/host-services.png>
81
82 <h2>Render your config</h2>
83 <p>When you have made all of the changes you need you will need to
84 render the Director configuration. Return to the Director menu,
85 select Config Deployment, and then select Render config.</p>
86
87 <h2>Self Service API</h2>
88 <p>In this last section we will look at what I think is the best feature
89 of Director which is the self service API. To enroll a host template
90 in the self service API, select the host template, select the agent
91 tab, and select generate self service api key. That's it!
92 The string of letters and numbers is the API key associated with this
93 host template. Hosts can be enrolled with this API key and Icinga
94 will automatically assign the host to this template. With proper
95 structuring, you can have hosts be completely provisioned without
96 touching Director. In the next article, we will use this to enroll
97 a host in Icinga with a shell script.</p>
98<p>
99<hr>
100Consider <a href=../donate.html>donating</a> if this article was useful.
101<a class=qr href=../images/bitcoin.png>[BTC]</a>
102</p>
103 </main>
104 <footer>
105 <a href=../kb.html>Knowledge Base</a>
106 <br>
107 <a href=../index.html>www.chudnick.com</a>
108 </footer>
109
110</body>
111</html>
112
diff --git a/articles/icinga-influx.html b/articles/icinga-influx.html
new file mode 100644
index 0000000..8d96c88
--- /dev/null
+++ b/articles/icinga-influx.html
@@ -0,0 +1,133 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' href='../style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1>Integrating InfluxDB and Icinga</h1></header>
12 <main>
13 <p>Icinga2 has built-in support for writing monitoring data to InfluxDB.
14 This makes Icinga quite extensible as it allows for other programs to read
15 the gathered data from InfluxDB. For example, Icinga does not have built-in
16 graphing support. But monitoring data can be written to InfluxDB and then
17 consumed by a dedicated graphing tool like Grafana.</p>
18
19 <h2>Install Packages</h2>
20 <p>Let's install a few necessary packages</p>
21
22 <pre><code>apt install influxdb influxdb-client ssl-cert</code></pre>
23
24 <h2>Generate self-signed certificate</h2>
25 <p>Now generate a self-signed certificate for accessing InfluxDB over TLS</p>
26
27 <pre><code>make-ssl-cert generate-default-snakeoil
28usermod -aG ssl-cert influxdb</code></pre>
29
30 <h2>Create Database and Users</h2>
31 <p>Start and enable the InfluxDB service</p>
32
33 <pre><code>systemctl enable --now influxdb</code></pre>
34
35 <p>Now we'll create our database and users. We'll be creating 3 users with
36 different access rights. An admin user with full control over the database, a
37 user with write access that Icinga will use to write data to the database, and
38 a read-only user to allow external programs to read data from the database.</p>
39
40 <pre><code>influx -ssl -unsafeSsl -execute "create database icinga2; create user admin with password '<em>changeme</em>'; create user icingauser with password '<em>changeme</em>'; create user readonly with password '<em>changeme</em>'; grant all to admin; grant write on icinga2 to icingauser; grant read on icinga2 to readonly;"
41</code></pre>
42
43<h2>Configuration Files</h2>
44
45 <p>Then write InfluxDB's configuration file at
46 <em>/etc/influxdb/influxdb.conf</em></p>
47
48 <pre><code>reporting-enabled = false
49[meta]
50 dir = "/var/lib/influxdb/meta"
51[data]
52 dir = "/var/lib/influxdb/data"
53 wal-dir = "/var/lib/influxdb/wal"
54[coordinator]
55[retention]
56[shard-precreation]
57[monitor]
58[http]
59 enabled = true
60 bind-address = ":8086"
61 auth-enabled = true
62 https-enabled = true
63 https-certificate = "/etc/ssl/certs/ssl-cert-snakeoil.pem"
64 https-private-key = "/etc/ssl/private/ssl-cert-snakeoil.key"
65[ifql]
66[logging]
67[subscriber]
68[[graphite]]
69[[collectd]]
70[[opentsdb]]
71[[udp]]
72[continuous_queries]
73[tls]
74 min-version = "tls1.2"</code></pre>
75
76 <p>And restart InfluxDB to pickup the changes</p>
77
78 <pre><code>systemctl restart influxdb</code></pre>
79
80 <p>Then we need to configure Icinga to write data to our database. Start by
81 enabling the influxdb feature in Icinga</p>
82
83 <pre><code>icinga2 feature enable influxdb</code></pre>
84
85 <p>Now we tell Icinga how to write to our database. Open the configuration
86 file at <em>/etc/icinga2/features-available/influxdb.conf</em> and replace
87 with the following</p>
88
89 <pre><code>object InfluxdbWriter \"influxdb\" {
90 host = "127.0.0.1"
91 port = 8086
92 username = "icingauser"
93 password = "<em>icinga_password</em>"
94 ssl_enable = true
95 database = "icinga2"
96 flush_threshold = 1024
97 flush_interval = 10s
98 host_template = {
99 measurement = "$host.check_command$"
100 tags = {
101 hostname = "$host.name$"
102 }
103 }
104 service_template = {
105 measurement = "$service.check_command$"
106 tags = {
107 hostname = "$host.name$"
108 service = "$service.name$"
109 }
110 }
111}</code></pre>
112
113 <p>And finally restart Icinga to make those changes live.</p>
114
115 <pre><code>systemctl restart icinga2</code></pre>
116
117 <p>Icinga2 will now be writing the data it collects to your InfluxDB instance.</p>
118
119 </main>
120<p>
121<hr>
122Consider <a href=../donate.html>donating</a> if this article was useful.
123<a class=qr href=../images/bitcoin.png>[BTC]</a>
124</p>
125 </main>
126 <footer>
127 <a href=../kb.html>Knowledge Base</a>
128 <br>
129 <a href=../index.html>www.chudnick.com</a>
130 </footer>
131</body>
132</html>
133
diff --git a/articles/icinga-master.html b/articles/icinga-master.html
new file mode 100644
index 0000000..0cafcdd
--- /dev/null
+++ b/articles/icinga-master.html
@@ -0,0 +1,276 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' href='../style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11<header><h1>Icinga2 Master Installation</h1></header>
12<main>
13<p>
14This tutorial will cover the installation of the Icinga2
15monitoring application master node. This includes the base
16program, the web frontend, and the web-based configuration tool.
17This guide was made for Debian but should be similar
18on other distributions.
19</p>
20<p>
21I have a script available to automate the steps described in this
22tutorial available
23<a href=https://git.chudnick.com/server-scripts/tree/monitoring/icinga-master>from my git repo</a>.
24<h2>Install Packages</h2>
25<p>Here we will install the required packages. Icinga can use either MySQL
26or PostgreSQL, however this tutorial will use MySQL/MariaDB.</p>
27<pre><code>apt install icinga2 icingaweb2 icinga2-ido-mysql icingaweb2-module-director monitoring-plugins monitoring-plugins-contrib default-mysql-server</code></pre>
28<h2>Secure MySQL</h2>
29<p>This step is optional but strongly recommended.
30The mysql_secure_installation script will harden your MySQL instance.</p>
31<pre><code>mysql_secure_installation</code></pre>
32<p>I recommend the following responses:
33<ul>
34 <li><em>Switch to unix_socket authentication?</em><strong> Y</strong></li>
35 <li><em>Change the root password?</em><strong> Y</strong></li>
36 <li><em>Remove anonymous users?</em><strong> Y</strong></li>
37 <li><em>Disallow root login remotely?</em><strong> Y</strong></li>
38 <li><em>Remove the test database and access to it?</em><strong> Y</strong></li>
39 <li><em>Reload privilege tables now?</em><strong> Y</strong></li>
40</ul>
41</p>
42
43<h2>Create Monitoring Database</h2>
44<p>The next several sections will cover creating databases for the various
45parts of Icinga. We'll start with the monitoring database.
46The following command creates a MySQL database named <em>icinga2</em>
47and grants permissions to a user named <em>ido_admin</em>. These values
48are arbitrary, but I use them throughout the tutorial so I recommend leaving them
49as is. You should definitely change the password though, which in the command
50is <em>change me</em>. You will need this password and the passwords for the
51other databases later, so make sure you save them.</p>
52<pre><code>mysql -u root -e "CREATE DATABASE icinga2; GRANT SELECT, INSERT, UPDATE, DELETE, DROP, CREATE VIEW, INDEX, EXECUTE ON icinga2.* TO <em>ido_admin</em>@'localhost' IDENTIFIED BY '<em>change me</em>'; FLUSH PRIVILEGES;</code></pre>
53
54<p>We then need to import the ido schema into the database.</p>
55
56<pre><code>mysql -u root icinga2 &lt;/usr/share/icinga2-ido-mysql/schema/mysql.sql</code></pre>
57
58<p>After importing the schema, we then write the configuration file that tells
59the monitoring module how to connect to the database.</p>
60<pre><code><strong>/etc/icinga2/features-available/ido-mysql.conf</strong>
61library "db_ido_mysql"
62object IdoMysqlConnection "ido-mysql" {
63 user = "ido_admin",
64 password = "<em>ido_password</em>",
65 host = "localhost",
66 database = "icinga2"
67}"</code></pre>
68
69<p>And finally we enable the monitoring module in Icinga.</p>
70<pre><code>icinga2 feature enable ido-mysql</code></pre>
71
72<h2>Create Icingaweb2 Database</h2>
73<p>This step is nearly identical to the last. This time we create a database
74named <em>icingaweb2</em> and grant permissions to the user named
75<em>icingaweb2_admin</em>.</p>
76<pre><code>mysql -u root -e "CREATE DATABASE icingaweb2;GRANT ALL ON icingaweb2.* TO 'icingaweb2_admin'@'localhost' IDENTIFIED BY '<em>changeme</em>'; FLUSH PRIVILEGES;</code></pre>
77
78<p>Again we will need to import required schema into the database.</p>
79<pre><code>mysql -u root icingaweb2 &lt;/usr/share/icingawbe2/etc/schema/mysql.schema.sql</code></pre>
80
81
82<p>In this step we create the initial admin user that will be used to login
83to the web interface. As is, this would create a user named <em>admin</em>
84with the password <em>changme</em>. You should at least change the password.</p>
85<pre><code>passhash="$(php -r "echo password_hash(\"<em>changeme</em>\", PASSWORD_DEFAULT);")"
86mysql -u root -e "USE icingaweb2; INSERT INTO icingaweb_user (name, active, password_hash) VALUES (\"<em>admin</em>\", 1, \"$passhash\"); FLUSH PRIVILEGES;"</code></pre>
87
88<h2>Create Icinga Director Database</h2>
89<p>Here we create the database for Director. Director will require more
90configuration later, so for now we will just be creating the database.</p>
91<pre><code>mysql -u root -e "CREATE DATABASE director CHARACTER SET 'utf8'; GRANT ALL on director.* TO 'director'@'localhost' IDENTIFIED BY '$director_password';FLUSH PRIVILEGES;"</code></pre>
92
93<h2>Setup Icinga2 API</h2>
94<p>Run the following command to initialize the Icinga API.</p>
95<pre><code>icinga2 api setup</code></pre>
96<p>And then restart Icinga to apply the changes.</p>
97<pre><code>systemctl restart icinga2</code></pre>
98
99<h2>Configure Web Server</h2>
100<p>In this section we will configure the web server for accessing
101Icinga's web interface and Director configuration tool.
102This tutorial will use nginx but apache could be used as well.
103We'll start by installing the necessary packages.</p>
104<pre><code>apt install nginx php-fpm</code></pre>
105<p>Then we need to create the site configuration file.<p>
106<pre><code><strong>/etc/nginx/sites-available/icingaweb2.conf</strong>
107server {
108 listen 80;
109 server_name <em>monitoring.example.com</em>
110 location ~ ^/icingaweb2/index\.php(.*)$ {
111 fastcgi_pass unix:/var/run/php/php-fpm.sock;
112 fastcgi_index index.php;
113 include fastcgi_params;
114 fastcgi_param SCRIPT_FILENAME /usr/share/icingaweb2/public/index.php;
115 fastcgi_param ICINGAWEB_CONFIGDIR /etc/icingaweb2;
116 fastcgi_param REMOTE_USER $remote_user;
117 }
118
119 location ~ ^/icingaweb2(.+)? {
120 alias /usr/share/icingaweb2/public;
121 index index.php;
122 try_files $1 $uri $uri/ /icingaweb2/index.php$is_args$args;
123 }
124
125 <em># Not strictly necessary but allows you to get to icinga without
126 # specifying /icingaweb2 in the URL.</em>
127 location = / {
128 return 302 http://$host/icingaweb2;
129 }
130
131}</code></pre>
132<p>And then restart nginx to pick up the changes.</p>
133<pre><code>systemctl restart nginx</code></pre>
134
135<p>At this point we are done with the Icinga setup module and so we
136can disable it.</p>
137<pre><code>icingacli module disable setup</code></pre>
138
139<h2>Write Configuration Files</h2>
140<p>In this section we will write several configuration files. Icinga uses
141the INI format for its web interface configuration files.</p>
142<p>In this first file we tell Icinga about the various resources it should have
143access to. These resources are the three databases created previously.
144Replace the password in each section with the corresponding password you set
145for that database earlier.</p>
146<pre><code><strong>/etc/icingaweb2/resources.ini</strong>
147[icinga2]
148type = "db"
149db = "mysql"
150host = "localhost"
151port = ""
152dbname = "icinga2"
153username = "ido_admin"
154password = "<em>ido password</em>"
155charset = ""
156use_ssl = "0"
157
158[icingaweb2]
159type = "db"
160db = "mysql"
161host = "localhost"
162port = ""
163dbname = "icingaweb2"
164username = "icingaweb2_admin"
165password = "<em>ido password</em>"
166charset = ""
167use_ssl = "0"
168
169
170[director]
171type = "db"
172db = "mysql"
173host = "localhost"
174port = ""
175dbname = "director"
176username = "director"
177password = "<em>director password</em>"
178charset = "utf8"
179use_ssl = "0"
180</code></pre>
181
182<p>This file controls the authentication settings for the web interface.
183Here we tell Icinga to look at the icingaweb2 database for
184authentication purposes.</p>
185<pre><code><strong>/etc/icingaweb2/authentication.ini</strong>
186[icingaweb2]
187backend = "db"
188resource = "icingaweb2"</code></pre>
189
190<p>Now we tell icinga which users should have admin permissions.
191If you changed the username value from <em>admin</em> previously, be sure to update
192it here.</p>
193<pre><code><strong>/etc/icingaweb2/roles.ini</strong>
194[admins]
195users = "<em>admin</em>"
196resource = "icingaweb2"</code></pre>
197
198<p>Enable the web interface monitoring module.</p>
199<pre><code>icingacli module enable monitoring</code></pre>
200<p>Then write the configuration file pointing the monitoring module to the
201monitoring database.</p>
202<pre><code><strong>/etc/icingaweb2/modules/monitoring/backends.ini</strong>
203[icinga]
204type = "ido"
205resource = "icinga2"</code></pre>
206
207<p>Here we configure Icinga to use the API for communication.
208You will need to get your unique API password generated during the API setup from
209from <strong>/etc/icinga2/conf.d/api-users.conf</strong>.
210<em>hostname</em> should be the FQDN of the server.</p>
211<pre><code><strong>/etc/icingaweb2/modules/monitoring/commandtransports.ini</strong>
212[icinga2]
213transport = "api"
214host = <em>hostname</em>
215port = "5665"
216username = "root"
217password = "<em>api password</em>"</code></pre>
218
219<p>Lastly, tell Icinga to protect variables with potentially sensitive values.</p>
220<pre><code><strong>/etc/icingaweb2/modules/monitoring/config.ini</strong>
221[security]
222protected_customvars = "*pw*,*pass*,*community*"</code></pre>
223
224
225<h2>Configure Director</h2>
226<p>This section will cover configuring Director configuration tool.</p>
227<p>Create Director module configuration directory.</p>
228<pre><code>mkdir -p /etc/icingaweb2/modules/director</code></pre>
229
230<p>Write the Director configuration file.</p>
231<pre><code><strong>/etc/icingaweb2/modules/director/config.ini</strong>
232[db]
233resource = "director"</code></pre>
234
235<p>Enable Director module and run the initial migration.</p>
236<pre><code>icingacli module enable director
237icingacli director migration run</code></pre>
238
239<p>Write Director kickstart configuration file.</p>
240<pre><code><strong>/etc/icingaweb2/modules/director/kickstart.ini</strong>
241[config]
242endpoint = "<em>hostname</em>"
243username = "root"
244password = "<em>api password</em>"</code></pre>
245
246<p>Kickstart Director, then render and deploy the configuration.</p>
247<pre><code>icingacli director kickstart run
248icingacli director config render
249icingacli director config deploy</code></pre>
250
251<p>Director is setup at this point so we will shred the unneeded configuration
252file containing sensitive information.</p>
253<pre><code>shred -uz /etc/icingaweb2/modules/director/kickstart.ini</code></pre>
254
255<h2>Login to your Monitoring Instance</h2>
256<p>You are now ready to login to your monitoring instance with the admin
257user created previously. Open a web browser and go to
258http://<em>hostname</em>/icingaweb2. You should see a screen similar to this:</p>
259<a href=../images/icinga-login.png><img src=../images/icinga-login.png alt="Icinagweb2 Login Screen"></a>
260
261<h2>Next Steps</h2>
262<p>In the following articles we will go through setting up Icinga2 agents on servers, and configure your monitoring instance through Icinga Director.</p>
263<p>
264<hr>
265Consider <a href=../donate.html>donating</a> if this article was useful.
266<a class=qr href=../images/bitcoin.png>[BTC]</a>
267</p>
268 </main>
269 <footer>
270 <a href=../kb.html>Knowledge Base</a>
271 <br>
272 <a href=../index.html>www.chudnick.com</a>
273 </footer>
274</body>
275</html>
276
diff --git a/articles/luks.html b/articles/luks.html
new file mode 100644
index 0000000..d2bbc5e
--- /dev/null
+++ b/articles/luks.html
@@ -0,0 +1,132 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' href='../style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1>LUKS Block Device Encryption</h1></header>
12 <main>
13 <p>Linux Unified Key Setup (LUKS) is a method for encrypting
14 block devices that is built-in to the Linux Kernel. In this tutorial
15 I will be showing how to create an encrypted USB drive with LUKS, but
16 this process is applicable to other types of storage.
17 <strong>This process will wipe all data on the device that you
18 encrypt so make backups beforehand if needed</strong>.</p>
19
20 <h2>Install Packages</h2>
21 <p>Install cryptsetup and its dependencies</p>
22
23 <pre><code>apt install cryptsetup</code></pre>
24
25 <h2>Prepare the Drive</h2>
26 <p>If the device you are encrypting was previously used, you will
27 want to completely overwrite any data on it before encryption. This
28 can be done using <strong>dd</strong> as shown below. This could take
29 a very long time depending on the size and type of your drive.
30 Be sure that you enter the correct path to your drive as the
31 argument to <strong>of</strong>, and do not specify a partition:
32 <strong>/dev/sdb</strong> is correct, <strong>/dev/sdb1</strong> is
33 wrong. Obviously this will destroy any data on the device so be
34 absolutely sure you specify the correct device in the command
35 and have backups of data previously stored if needed.</p>
36
37 <pre><code>dd if=/dev/zero of=<em>/dev/sdX</em> status=progress</code></pre>
38
39 <h2>Encrypt the Drive</h2>
40 <p><strong>cryptsetup</strong> is the main command used to perform
41 LUKS-related tasks. This main command is followed by a subcommand
42 that specifies which action to perform. To create a LUKS partition
43 on a drive we need to use the subcommand <strong>luksFormat</strong>.
44 We also use the type option to explicitly say to use LUKS version 2
45 encryption. Run the command and then enter and confirm the
46 encryption password.</p>
47
48 <pre><code>cryptsetup --type luks2 luksFormat <em>/dev/sdX</em></code></pre>
49
50 <p>Now we need to open and map the encrypted LUKS device. This is done
51 by using the <strong>luksOpen</strong> subcommand. This subcommand takes
52 the device as the first argument and then a map target as the second. The
53 map target can be any string as long as a map does not already exist with
54 that name. In the example I will use <em>crypt</em>.
55
56 <pre><code>cryptsetup luksOpen <em>/dev/sdX crypt</em></code></pre>
57
58 <p>And then we just need to create a filesystem on the device; I will
59 be making an ext4 filesystem in the example. To
60 interact with an encrypted drive after it has been opened you need
61 to refer to its device mapper target, which is found under /dev/mapper.
62 Since we used <em>crypt</em> as the map target, our encrypted drive
63 is /dev/mapper/<em>crypt</em>. </p>
64
65 <pre><code>mkfs.ext4 /dev/mapper/<em>crypt</em></code></pre>
66
67 <p>After creating the filesystem created the encrypted drive
68 can now be mounted and used like any other device. Remember that
69 when mounting the device you refer to the device mapper target
70 (mount /dev/mapper/<em>crypt</em> /mnt/crypt).</p>
71
72 <p>In addition to unmounting the filesystem you should always close
73 the device mapping before removing your encrypted drive. This is
74 done with the <strong>luksClose</strong> subcommand and takes
75 the device mapping as the argument.</p>
76
77 <pre><code>cryptsetup luksClose /dev/mapper/<em>crypt</em></code></pre>
78
79 <h2>The LUKS Header</h2>
80 <p>The LUKS header sits at the front of your encrypted drive and is
81 responsible for managing access to the device. If the header is
82 damaged accessing your encrypted data will not be possible. Because of
83 this, you may want to make backups of the header, but before doing so
84 you need to weigh the risks and benefits.</p>
85
86 <p>The obvious benefit is that
87 in the event of damage to the LUKS header, you can easily restore a
88 backup and regain access to the data. However, having a backup of the
89 header makes it harder to wipe the LUKS device. Without a header
90 backup, overwriting the LUKS header on the device is enough to securely
91 wipe the drive. With backups, you need to either destroy all header
92 backups or overwrite all encrypted data on the device. The other main risk
93 is that an encryption password that is valid at the time you make a
94 backup will always be valid for that backup. For example, say you change
95 the encryption password on your device after making a backup because it
96 has been compromised. An attacker would be able to restore the header
97 backup and then use the compromised password to access the data.</p>
98
99 <p>The cryptsetup documentation refers to creating header backups
100 as making a trade-off between safety and security. You need to make a
101 decision based on your individual use-case. It's a good idea to
102 routinely update your header backups if you do choose to make them</p>
103
104 <p>When creating or restoring a header backup you always refer to the
105 block device in the command, not the device mapper taget. To create
106 a header backup:</p>
107
108 <pre><code>cryptsetup luksHeaderBackup <em>/dev/sdX</em> --header-backup-file <em>path/to/backup</em></code></pre>
109
110 <p>To restore a header from a backup:</p>
111
112 <pre><code>cryptsetup luksHeaderRestore <em>/dev/sdX</em> --header-backup-file <em>path/to/backup</em></code></pre>
113
114 <p>Note that is not necessary to store header backups on an encrypted
115 device. I would recommend storing backups on at least one non-encrypted
116 drive in case of an emergency.</p>
117
118 </main>
119<p>
120<hr>
121Consider <a href=../donate.html>donating</a> if this article was useful.
122<a class=qr href=../images/bitcoin.png>[BTC]</a>
123</p>
124 </main>
125 <footer>
126 <a href=../kb.html>Knowledge Base</a>
127 <br>
128 <a href=../index.html>www.chudnick.com</a>
129 </footer>
130</body>
131</html>
132
diff --git a/articles/mail-server.html b/articles/mail-server.html
new file mode 100644
index 0000000..12a3264
--- /dev/null
+++ b/articles/mail-server.html
@@ -0,0 +1,723 @@
1<!DOCTYPE html>
2<html lang=en>
3<head>
4<title></title>
5<meta charset="utf-8"/>
6<link rel="shortcut icon" href="favicon.ico"/>
7<link rel='stylesheet' href='../style.css'/>
8<meta name="viewport" content="width=device-width, initial-scale=1">
9</head>
10<body>
11<header><h1>Postfix and Dovecot Mail Server</h1></header>
12<main>
13
14<p>Postfix and dovecot will be the two primary pieces of our mail sever.
15Postfix is the mail transport agent that handles the sending and
16receiving of mail and dovecot is the IMAP server that will allow us to
17access our mail from a mail client such as mutt. The server will also
18have several other supporting components, a complete list of which is:</p>
19
20<ul>
21 <li><em>SpamAssassin</em> for spam filtering</li>
22 <li><em>OpenDKIM</em> for DKIM verification and signing</li>
23 <li><em>Postgrey</em> for greylisting</li>
24 <li><em>Policyd-SPF</em> for SPF verification</li>
25 <li><em>OpenDMARC</em> for DMARC verification</li>
26</ul>
27
28<p>You can use <a href=https://git.chudnick.com/mail-tools/tree/server/deploy-server>
29this script</a> I have written to automate this process, but I would
30recommend that you run through the tutorial first to understand
31what is being done.</p>
32
33<p>Please note that this tutorial is loosely intended for small personal mail
34servers. Using PAM for authentication, as is done here, is not a scalable solution
35for working with a large number of users. I do plan on covering Dovecot LDAP
36authentication at some point which would be a better solution in an enterprise
37setting.</p>
38
39<h2>Install Packages</h2>
40<p>Let's start by installing the required packages. Note that if you already
41have Apache installed on the server, replace <em>python3-certbot-nginx</em>
42with <em>python3-certbot-apache</em>.</p>
43<pre><code>apt install postfix dovecot-imapd dovecot-sieve opendkim opendkim-tools spamassassin gnupg postgrey postfix-policyd-spf-python opendmarc dbconfig-no-thanks certbot python3-certbot-nginx</code></pre>
44<p>During the installation of Postfix you will get a Debconf prompt in which
45you need to select "Internet Site" and then provide your domain name,
46<strong>example.com</strong>.</p>
47
48<h2>Get a certificate</h2>
49<p>Now we'll use Certbot to get a certificate for our server. If you are
50using Apache replace <em>nginx</em> with <em>apache2</em>.</p>
51
52<pre><code>systemctl stop nginx
53certbot certonly --standalone -d <strong>mail.example.com</strong>
54systemctl start nginx</code></pre>
55
56<h2>Postfix Main Configuration</h2>
57<p>In this section we will be doing the bulk of the postfix configuration.
58The postconf command used throughout appends (or changes)
59the specified configuration item in /etc/postfix/main.cf</p>
60
61<h3>Network Configuration</h3>
62
63<p>Let's start by configuring some network and domain information.</p>
64
65<pre><code>postconf -e "myorigin = <strong>example.com</strong>"
66postconf -e "mydestination = \$myhostname, \$mydomain, localhost"
67postconf -e "mynetworks = 127.0.0.0/8 [::1]/128"
68postconf -e "myhostname = <strong>mail.example.com</strong>"
69</code></pre>
70
71<p>Next, point postfix to the cerbot key and certificate, as well as the distro's
72CA certificates.</p>
73
74<pre><code>postconf -e "smtpd_tls_key_file=/etc/letsencrypt/live/<strong>mail.example.com</strong>/privkey.pem"
75postconf -e "smtpd_tls_cert_file=/etc/letsencrypt/live/<strong>mail.example.com</strong>/fullchain.pem"
76postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt"
77</code></pre>
78
79<p>Harden the TLS configuration by forcing strong
80protocols and ciphers, and requiring that authentication occur only over an
81encrypted session.</p>
82<pre><code><em># Require authentication over TLS and optionally use it for sending and receiving mail</em>
83postconf -e "smtpd_tls_auth_only = yes"
84postconf -e "smtpd_tls_security_level = may"
85postconf -e "smtp_tls_security_level = may"
86
87<em># Force the use of TLSv1.2 or TLSv1.3</em>
88postconf -e 'smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
89postconf -e 'smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
90postconf -e 'smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
91postconf -e 'smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
92
93<em># Prefer server ciphers</em>
94postconf -e "tls_preempt_cipherlist = yes"
95
96<em># Force strong ciphers</em>
97postconf -e "smtpd_tls_ciphers = high"
98postconf -e "smtpd_tls_mandatory_ciphers = high"
99postconf -e "smtp_tls_ciphers = high"
100postconf -e "smtp_tls_mandatory_ciphers = high"
101postconf -e "smtpd_tls_exclude_ciphers = aNULL, eNULL, EXP, LOW, MEDIUM, PSK, SRP, SHA1, kRSA, CAMELLIA, ARIA, DSS, RSA+AES, ADH, AECDH"
102postconf -e "smtp_tls_exclude_ciphers = aNULL, eNULL, EXP, LOW, MEDIUM, PSK, SRP, SHA1, kRSA, CAMELLIA, ARIA, DSS, RSA+AES, ADH, AECDH"
103</code></pre>
104
105<h3>Local Recipients and Aliases</h3>
106
107<p>Here we configure the bulk of the postfix built-in security settings which are
108structured as a series of access restrictions. Do not edit these settings without
109first reading the Postfix documentation as an incorrect change could inadvertently
110make your server an open relay.</p>
111
112<pre><code>postconf -e "smtpd_helo_required = yes"
113postconf -e "smtpd_sender_login_maps = proxy:hash:/etc/postfix/login_maps"
114postconf -e "smtpd_helo_restrictions = reject_unknown_helo_hostname, reject_non_fqdn_helo_hostname"
115postconf -e "smtpd_sender_restrictions = reject_sender_login_mismatch, reject_non_fqdn_sender, reject_unknown_sender_domain"
116postconf -e "smtpd_recipient_restrictions = reject_non_fqdn_recipient, reject_unknown_recipient_domain, permit_sasl_authenticated, reject_unauth_destination, check_policy_service unix:private/postgrey, check_policy_service unix:private/policyd-spf, reject_rbl_client zen.spamhaus.org"
117postconf -e "smtpd_relay_restrictions = permit_sasl_authenticated, reject_unauth_destination"
118postconf -e "smtpd_data_restrictions = reject_unauth_pipelining"
119
120<em># Disable VRFY command to prevent harvesting of user accounts on system</em>
121postconf -e "disable_vrfy_command = yes"
122
123<em># Change smptd banner (hide distribution)</em>
124postconf -e "smtpd_banner = \$myhostname ESMTP \$mail_name"</code></pre>
125
126<p>Now, configure the local mail recipients and some aliases. We'll create
127an account called <strong>mailadmin</strong> to receive mail addressed to
128several other accounts. This is to keep <em>administrative</em> mail separate, but
129you can certainly alias these to your main account later if you would prefer to see
130it there.</p>
131
132<pre><code><em># Set a custom local_recipient_maps here in order to avoid accepting mail for all local accounts</em>
133postconf -e "local_recipient_maps = proxy:hash:/etc/postfix/local_maps \$alias_maps"
134
135<em># You will need to manually set a password later to login as mailadmin</em>
136adduser --disabled-login --shell /usr/sbin/nologin --gecos "" mailadmin
137echo "# postfix aliases
138postmaster: mailadmin
139root: mailadmin
140dmarc: mailadmin
141" &gt; /etc/aliases
142
143<em># Update address databases</em>
144echo "mailadmin@<em>mail.example.com</em> mailadmin" &gt; /etc/postfix/login_maps
145echo "mailadmin mailadmin" &gt; /etc/postfix/local_maps
146newaliases
147postmap /etc/postfix/login_maps
148postmap /etc/postfix/local_maps
149</code></pre>
150
151<h3>Mail Delivery</h3>
152
153
154<p>These commands configure our mail delivery preferences. Mail will be
155delivered inside a user's home folder with a maildir-style mailbox using
156dovecot.</p>
157
158<pre><code><em># Maildir delivery to $HOME/Mail/Inbox/</em>
159postconf -e "home_mailbox = Mail/Inbox/"
160<em># Deliver mail with Dovecot</em>
161postconf -e "mailbox_command = /usr/lib/dovecot/deliver"</code></pre>
162
163<h3>Header and Body Checks</h3>
164
165<p>Header and body checks allow for some simple content filtering within Postfix.
166This is done by scanning a message line by line for a configured regex string,
167nothing more. For example, the first header check listed will reject a message
168with an attachment of <em>ransomware.exe</em> but will not block it if sent with
169no extension. This is mostly a protection against uneducated users and poorly
170written mail clients. Other checks block vulnerabilities and improve privacy.</p>
171
172<p>Create a new file <strong>/etc/postfix/header_checks</strong>, then open it in a
173text editor and add the following</p>
174<pre><code><em># Block files with common executable extensions</em>
175/name=[^&gt;]*\.(exe|pif|com|dll|vbs|bat|sh|bash|so|zip|tar|gz|cpio)/ REJECT
176
177<em># Block message/partial vulnerability</em>
178/message\/partial/ REJECT
179
180<em># Remove Received string that is created when spamassassin reinjects message into postfix</em>
181<em># This is to prevent leaking the userid of the spamassassin user</em>
182/^Received:.*userid.*/ IGNORE
183
184<em># Remove User-Agent strings from headers</em>
185/^User-Agent: .*/ IGNORE</code></pre>
186
187<p>Create another new file <strong>/etc/postfix/body_checks</strong>, and add this</p>
188<pre><code><em># Block messages with iframes</em>
189/&lt;iframe/ REJECT" &gt; /etc/postfix/body_checks</code></pre>
190
191<p>And then run these commands to point postfix to the check files.</p>
192<pre><code>postconf -e "header_checks = regexp:/etc/postfix/header_checks"
193postconf -e "body_checks = regexp:/etc/postfix/body_checks"</code></pre>
194
195<h2>Postfix Master Configuration</h2>
196<h3>SMTP client</h3>
197<p>This simple command configures the SMTP client process that is responsible
198for sending your mail to other mail servers.</p>
199
200<pre><code>postconf -M "smtp/unix=smtp unix - - y - - smtp"</code></pre>
201
202<h3>Postscreen and SMTP Recipient</h3>
203<p>Postscreen is a kind of firewall that sits in front of the Postfix SMTPD
204process and receives all incoming traffic. Postscreen will drop connections
205from IPs on a DNS blacklst, or from clients that violate the SMTP protocol by
206speaking out of turn or sending non-SMTP commands. This adds up to less spam
207connections and therefore a much lighter workload for your server.</p>
208
209<pre><code>postconf -M "smtp/inet=smtp inet n - y - 1 postscreen"
210postconf -M "smtpd/pass=smtpd pass - - y - - smtpd"
211postconf -P "smtpd/pass/content_filter=spamassassin"
212postconf -M "tlsproxy/unix=tlsproxy unix - - y - 0 tlsproxy"
213postconf -M "dnsblog/unix=dnsblog unix - - y - 0 dnsblog"
214postconf -e "postscreen_dnsbl_sites = zen.spamhaus.org"
215postconf -e "postscreen_dnsbl_action = enforce"
216postconf -e "postscreen_greet_action = enforce"
217</code></pre>
218
219<h3>Submission over TLS (submissions)</h3>
220<p>Submission over TLS (aka submissions) is the process you will use to submit
221mail to your server from a mail client. These commands configure submissions to
222use a fully-encrypted session, as opposed to STARTTLS, and to only allow access
223to authenticated clients.</p>
224
225<pre><code>postconf -M "submissions/inet=submissions inet n - y - - smtpd"
226postconf -P "submissions/inet/smtpd_tls_wrappermode=yes"
227postconf -P "submissions/inet/smtpd_tls_security_level=encrypt"
228postconf -P "submissions/inet/smtpd_tls_auth_only=yes"
229postconf -P "submissions/inet/smtpd_sasl_auth_enable=yes"
230postconf -P "submissions/inet/smtpd_client_restrictions=permit_sasl_authenticated,reject"
231postconf -P "submissions/inet/smtpd_helo_restrictions="
232postconf -P "submissions/inet/smtpd_sender_restrictions=reject_sender_login_mismatch"
233postconf -P "submissions/inet/smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject"
234postconf -P "submissions/inet/syslog_name=postfix/submissions"
235postconf -P 'submissions/inet/smtpd_tls_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'
236postconf -P 'submissions/inet/smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'</code></pre>
237
238<h3>OPTIONAL - submission with mandatory STARTTLS</h3>
239<p>Having configured submission over TLS on port 465 this step is optional.
240STARTTLS is considered by some to be less secure than full-session TLS and
241may be vulnerable to exploitation.</p>
242
243<pre><code>postconf -M "submission/inet=submission inet n - y - - smtpd"
244postconf -P "submission/inet/smtpd_tls_security_level=encrypt"
245postconf -P 'submission/inet/smtpd_tls_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'
246postconf -P 'submission/inet/smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'
247postconf -P "submission/inet/smtpd_sasl_auth_enable=yes"
248postconf -P "submission/inet/smtpd_tls_auth_only=yes"
249postconf -P "submission/inet/syslog_name=postfix/submission"
250postconf -P "submission/inet/smtpd_helo_restrictions="
251postconf -P "submission/inet/smtpd_client_restrictions=permit_sasl_authenticated,reject"
252postconf -P "submission/inet/smtpd_helo_restrictions="
253postconf -P "submission/inet/smtpd_sender_restrictions=reject_sender_login_mismatch"
254postconf -P "submission/inet/smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject"
255</code></pre>
256
257<h3>SpamAssassin Configuration</h3>
258<p>Finally, this command tells Postfix how to interact with SpamAssassin.</p>
259
260<pre><code>postconf -M "spamassassin/unix=spamassassin unix - n n - - pipe user=debian-spamd argv=/usr/bin/spamc --socket=/var/run/spamd.sock -e /usr/sbin/sendmail -oi -f \${sender} \${recipient}" </code></pre>
261
262<h2>Dovecot Configuration</h2>
263<p>Dovecot configuration is usually split up into many different files under
264<strong>/etc/dovecot/conf.d/</strong> but here will be doing all of the
265configuration in the primary config file
266<strong>/etc/dovecot/dovecot.conf</strong>. Open that file with your editor
267of choice, clear all of its contents, and then replace it with the following.</p>
268
269<pre><code><em># /etc/dovecot/conf.d/10-auth.conf</em>
270disable_plaintext_auth = yes
271auth_username_format = %n
272auth_mechanisms = plain
273userdb {
274 driver = passwd
275}
276passdb {
277 driver = pam
278}
279
280<em># /etc/dovecot/conf.d/10-mail.conf</em>
281mail_location = maildir:~/Mail:INBOX=~/Mail/Inbox:LAYOUT=fs
282namespace inbox {
283 type = private
284 prefix =
285 separator = /
286 inbox = yes
287 subscriptions = yes
288 list = yes
289}
290
291<em># /etc/dovecot/conf.d/10-master.conf</em>
292service imap-login {
293# Run login processes in high-security mode (see: LoginProcess.txt in dovecot docs)
294service_count = 1
295# Disable unencrypted IMAP by setting port for plain IMAP to 0
296 inet_listener imap {
297 port = 0
298 }
299 inet_listener imaps {
300 port = 993
301 ssl = yes
302 }
303}
304
305<em># Allow postfix to use dovecot SASL</em>
306service auth {
307 unix_listener /var/spool/postfix/private/auth {
308 mode = 0660
309 user = postfix
310 group = postfix
311 }
312}
313
314<em># /etc/dovecot/conf.d/10-ssl.conf</em>
315ssl = required
316ssl_key = &lt;/etc/letsencrypt/live/<strong>mail.example.com</strong>/privkey.pem
317ssl_cert = &lt;/etc/letsencrypt/live/<strong>mail.example.com</strong>/fullchain.pem
318ssl_client_ca_dir = /etc/ssl/certs
319ssl_dh = &lt;/usr/share/dovecot/dh.pem
320
321<em># Mozilla intermediate compatibility</em>
322ssl_min_protocol = TLSv1.2
323ssl_cipher_list = ECDHE+ECDSA+AESGCM:ECDHE+aRSA+AESGCM:ECDHE+ECDSA+CHACHA20:ECDHE+aRSA+CHACHA20:DHE+aRSA+AESGCM:!aNULL:!eNULL
324
325ssl_prefer_server_ciphers = yes
326ssl_client_require_valid_cert = yes
327
328
329<em># /etc/dovecot/conf.d/15-lda.conf</em>
330protocol lda {
331 mail_plugins = \$mail_plugins sieve
332}
333
334<em># /etc/dovecot/conf.d/15-mailboxes.conf</em>
335namespace inbox {
336 mailbox Sent {
337 special_use = \Sent
338 auto = subscribe
339 }
340 mailbox Trash {
341 special_use = \Trash
342 auto = create
343 autoexpunge = 30d
344 }
345 mailbox Drafts {
346 special_use = \Drafts
347 auto = subscribe
348 }
349 mailbox Spam {
350 special_use = \Junk
351 auto = create
352 autoexpunge = 30d
353 }
354 mailbox Archive {
355 special_use = \Archive
356 auto = create
357 }
358}
359
360<em># /etc/dovecot/conf.d/20-imap.conf</em>
361imap_capability = +SPECIAL-USE
362
363<em># /etc/dovecot/conf.d/90-sieve.conf</em>
364plugin {
365 sieve = ~/.dovecot.sieve
366 sieve_default = /var/lib/dovecot/sieve/default.sieve
367 sieve_global = /var/lib/dovecot/sieve/
368}</code></pre>
369
370<p>Then create the default sieve filtering script at
371<strong>/var/lib/dovecot/sieve/default.sieve</strong></p>
372<pre><code>require ["fileinto", "mailbox"];
373/*
374* Discard mail that has a spam score greater than or equal to 10
375*/
376if header :contains "X-Spam-Level" "**********" {
377 discard;
378 stop;
379}
380/*
381* Discard messages marked as infected by a virus scanner
382*/
383if header :contains "X-Virus-Scan" "infected" {
384 discard;
385 stop;
386}
387/*
388* If message is marked as spam (and falls below discard threshold) put into spam mailbox
389*/
390if header :contains "X-Spam-Flag" "YES" {
391 fileinto "Spam";
392}</code></pre>
393
394<p>And compile the script</p>
395
396<pre><code>sievec /var/lib/dovecot/sieve/default.sieve</code></pre>
397
398
399<p>Finally, configure PAM authentication for dovecot at
400<strong>/etc/pam.d/dovecot</strong>. Append these changes leaving any include
401statements intact.</p>
402<pre><code>auth required pam_unix.so
403account required pam_unix.so</code></pre>
404
405<h2>OpenDKIM</h2>
406<p>DKIM is a mail-verification method that cryptographically signs mail
407to allow receivers to verify the authenticity of the sender. Our mail server
408will use DKIM to validate signatures on incoming mail and sign outgoing mail. DKIM
409requires a public key to be published via DNS, which will be done near the end of
410the guide.</p>
411
412<p>Start by generating the DKIM key</p>
413
414<pre><code>opendkim-genkey -D /etc/dkimkeys -d <em>example.com</em> -s mail
415chown opendkim: /etc/dkimkeys/*
416chmod 600 /etc/dkimkeys/*
417mv /etc/dkimkeys/mail.private /etc/dkimkeys/mail.pem</code></pre>
418
419<p>Here we make a directory for the opendkim socket inside the postfix chroot and
420make it accessible to the postfix user.</p>
421
422<pre><code>mkdir /var/spool/postfix/opendkim
423chmod 770 /var/spool/postfix/opendkim
424chown opendkim:opendkim /var/spool/postfix/opendkim
425usermod -aG opendkim postfix</code></pre>
426
427<p>Edit the configuration file at <strong>/etc/opendkim.conf</strong>
428to be as follows:</p>
429
430<pre><code>On-BadSignature reject
431On-Security reject
432Syslog yes
433SyslogSuccess yes
434LogResults yes
435Canonicalization simple
436Mode sv
437OversignHeaders From
438Domain <strong>example.com</strong>
439Selector mail
440KeyFile /etc/dkimkeys/mail.pem
441UserID opendkim
442UMask 007
443Socket local:/var/spool/postfix/opendkim/opendkim.sock
444PidFile /run/opendkim/opendkim.pid
445TemporaryDirectory /run/opendkim
446InternalHosts 127.0.0.1
447TrustAnchorFile /usr/share/dns/root.key
448RequireSafeKeys True
449AlwaysAddARHeader True
450</code></pre>
451
452<h2>OpenDMARC</h2>
453<p>DMARC is another mail-verification technology that provides verification of the
454address seen by end-users and either or both of SPF and DKIM.
455
456<p>Like with OpenDKIM, we need to make a directory inside the postfix chroot
457for the socket and assign proper permissions.</p>
458<pre><code>mkdir /var/spool/postfix/opendmarc
459chmod 770 /var/spool/postfix/opendmarc
460chown opendmarc:opendmarc /var/spool/postfix/opendmarc
461usermod -aG opendmarc postfix
462</code></pre>
463
464<p>Now we write the configuration file at <strong>/etc/opendmarc.conf</strong></p>
465
466<pre><code>PidFile /run/opendmarc/opendmarc.pid
467PublicSuffixList /usr/share/publicsuffix/public_suffix_list.dat
468RejectFailures True
469Socket local:/var/spool/postfix/opendmarc/opendmarc.sock
470Syslog True
471SyslogFacility mail
472UMask 002
473UserID opendmarc
474HistoryFile /var/run/opendmarc/opendmarc.hist
475SPFIgnoreResults True
476SPFSelfValidate True
477</code></pre>
478
479<p>Then create the history file and set permissions.</p>
480
481<pre><code>touch /var/run/opendmarc/opendmarc.hist
482chown opendmarc:opendmarc /var/run/opendmarc/opendmarc.hist
483chmod 664 /var/run/opendmarc/opendmarc.hist
484</code></pre>
485
486<p>Now that both OpenDKIM and OpenDMARC are configured we can define them as milters
487in postfix. This will tell postfix to route mail through one or both of these milters
488depending on whether it is incoming or outgoing.</p>
489
490<pre><code>postconf -P "smtpd/pass/smtpd_milters=unix:opendkim/opendkim.sock,unix:opendmarc/opendmarc.sock"
491postconf -P "submissions/inet/smtpd_milters=unix:opendkim/opendkim.sock"
492<em># If you enabled submission on port 587 run this too</em>
493postconf -P "submission/inet/smtpd_milters=unix:opendkim/opendkim.sock"
494</code></pre>
495
496<h2>Postgrey</h2>
497<p>Postgrey implements a spam-filter technique known as greylisting, which
498always rejects mail on the first try and for a period of time afterwards known
499as the greylist period. The idea behind this being that legitimate senders will
500send the mail again later, while spammers, in a rush to send as many messages as
501possible before being blacklisted, will not.</p>
502
503<p>Postgrey ships with an extensive whitelist domains that are known
504to cause issues (mainly large providers that constantly send from different
505addresses). This whitelist file is located at
506<strong>/etc/postgrey/whitelist_clients</strong> and can be appended to include
507any domain you do not wish to be subject to greylisting.</p>
508
509<p>The configuration needed here is minimal, just open
510<strong>/etc/default/postgrey</strong> and make these changes</p>
511
512<pre><code>POSTGREY_OPTS="--unix=/var/spool/postfix/private/postgrey --privacy"
513POSTGREY_TEXT="Greylisted - see https://www.greylisting.org"</code></pre>
514
515<p>And then enable the service</p>
516
517<pre><code>systemctl enable --now postgrey</code></pre>
518
519<h2>Policyd-SPF</h2>
520<p>SPF is yet another mail-verification technology that uses DNS records to
521delegate specific servers as being authorized to send mail for the domain
522(and implicitly all other servers as unauthorized). Policyd-SPF will perform
523SPF checking of received mail and reject mail that fails SPF verfication.</p>
524
525<p>First, tell postfix how to access Policyd-SPF</p>
526
527<pre><code>postconf -e "policyd-spf_time_limit = 3600"
528postconf -M "policyd-spf/unix=policyd-spf unix - n n - 0 spawn user=policyd-spf argv=/usr/bin/policyd-spf"</code></pre>
529
530<p>And then edit the configuration file at
531<strong>/etc/postfix-policyd-spf-python/policyd-spf.conf</strong></p>
532
533<pre><code>debugLevel = 1
534TestOnly = 1
535HELO_reject = Fail
536Mail_From_reject = Fail
537Header_Type = AR
538<em># These settings increase false-positive risk</em>
539<em># Comment them if you want to reduce that risk</em>
540PermError_reject = True
541TempError_Defer = True</code></pre>
542
543
544<h2>SpamAssassin</h2>
545<p>SpamAssassin is a spam-filter that will scan all received mail and assign
546a spam score based on configured rules. SpamAssassin is much heavier and more
547resource-intensive than any of the previous spam-filtering/verification programs
548we have configured. The postfix spam-filtering philosophy emphasizes the use
549of lightweight checks before passing to an external content filter such as
550SpamAssassin. Ideally, non-legitimate mail will have already been caught by one
551of the previous methods, and SpamAssassin will only have to operate on a much
552smaller subset of the mail that is sent to our server.</p>
553
554<p>We have actually already told postfix to use SpamAssassin as a content filter
555so in this section we just need to edit the configuration file
556<strong>/etc/spamassassin/local.cf</strong>.</p>
557
558<pre><code><em># Clearly indicate message is spam to user</em>
559rewrite_header Subject *****SPAM*****
560rewrite_header From *****SPAM*****
561
562<em># Set required score to be marked as spam, 5.0 is default.</em>
563<em># Lower to make policy more strict or raise to be more lenient.</em>
564required_score 5.0
565
566<em># Attach original messages as text/plain instead of message/rfc822 to spam reports</em>
567report_safe 2
568
569<em>Do not implicitly trust mail based on IP address except localhost</em>
570trusted_networks 127.0.0.1/32
571</code></pre>
572
573<p>And finally make a few changes to the defaults file at
574<strong>/etc/default/spamassassin</strong></p>
575
576<pre><code>OPTIONS="--listen /var/run/spamd.sock --max-children 5"
577PIDFILE=/var/run/spamd.pid
578CRON=1</code></pre>
579
580<h2>Wrapping Up</h2>
581<p>At this point we have done all of the necessary configuration of the mail
582server programs. We have just a few more minor tasks before your mail server
583is operational.</p>
584
585<h3>Configure Firewall</h3>
586<p>We need to open the proper ports in the firewall. This example uses UFW.</p>
587
588<pre><code>ufw allow 25 comment "smtp"
589ufw allow 465 comment "submission over TLS"
590<em># Run this next command only if you enabled submission on port 587</em>
591ufw allow 587 comment "mail submission"
592ufw allow 993 comment "IMAP over TLS"
593ufw reload</code></pre>
594
595<h3>Restart services</h3>
596<p>Now let's restart the services to pick up any configuration changes.</p>
597
598<pre><code>systemctl restart postfix
599systemctl restart dovecot
600systemctl restart opendkim
601systemctl restart opendmarc
602systemctl enable --now spamassassin
603systemctl restart spamassassin
604systemctl restart postgrey</code></pre>
605
606<h3>DNS Entries</h3>
607<p>Finally, we needs to set some required DNS records to enable mail flow and
608verification. Begin by logging into your registrar or DNS host and editing
609your DNS records.</p>
610
611<h3>A Record</h3>
612<p>If you did not set a wildcard A record earlier, you will need to set one now
613for <strong>mail</strong>.
614Alternatively, if you are running the mail server on the same server as your
615website, you may want to instead make a CNAME record pointing mail to www.</p>
616
617<h3>MX Record</h3>
618<p>MX records tell servers attempting to send you mail where to send it. Open the
619MX records section on your registrar and add a new record. An MX
620record consists of a priority and a destination. Set the priority to 10 and the
621destination to <strong>mail</strong>, or whatever your subdomain for this mail
622server is. The host value can be left blank or may need to be set to "@"
623depending on your registrar.</p>
624
625<h3>DKIM TXT Record</h3>
626<p>Now we will set the three TXT records we need. Open the TXT records tab on
627your registrar.</p>
628
629<p>We'll set the DKIM record first. The command we ran to
630generate our DKIM keys also generates a DNS record for us which will be helpful
631here. Print that to the screen with:</p>
632
633<pre><code>cat /etc/dkimkeys/mail.txt</code></pre>
634
635<p>You should get a lengthy output that looks something like the following. The
636bolded portion is the value.</p>
637
638<pre><code>mail._domainkey IN TXT ( <strong>"v=DKIM1; h=sha256; k=rsa; "
639 "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz50PSYL0Ob+OlF/0B77rwlzLe7zF6JKnxQNtMqcOCZ0Dar2FPhSUSz1FR0YmNuoShjMogdgKeojIzgRUqwK5GZ5Lz456qiXWkfAtLPc6UQ/WPoyEBGbJpRBYPGWdN4VoNcHkk/I4csvXW6MOI55ghPOwDmootPkCzNPR6gmNAXMe0duS4Lb+bIjy9QMOxGYVUaQ/b+7xar+fWw"
640 "bA3DjQa3jTLCydzzJpjEMfVaKqNhQ4N+ve7O2Mb3LF5k5B977mtok/6POjVG5HY8g6Pba+GzMFItR6nJO5EE2fyfv6cNbRLsZiM+WQmqvDBst5ejaeapy86F5PdJFlX/TUgXjtuwIDAQAB"</strong> ) ; ----- DKIM key mail for example.com</code></pre>
641
642<p>You can cleanup the spacing of the value as your registrar should automatically
643handle any needed splitting of the record. The parts you need to paste into your
644registrar's web interface should then look like this.</p>
645
646<pre><code><em># Name/Host</em>
647mail._domainkey
648<em># TXT Value</em>
649"v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz50PSYL0Ob+OlF/0B77rwlzLe7zF6JKnxQNtMqcOCZ0Dar2FPhSUSz1FR0YmNuoShjMogdgKeojIzgRUqwK5GZ5Lz456qiXWkfAtLPc6UQ/WPoyEBGbJpRBYPGWdN4VoNcHkk/I4csvXW6MOI55ghPOwDmootPkCzNPR6gmNAXMe0duS4Lb+bIjy9QMOxGYVUaQ/b+7xar+fWwbA3DjQa3jTLCydzzJpjEMfVaKqNhQ4N+ve7O2Mb3LF5k5B977mtok/6POjVG5HY8g6Pba+GzMFItR6nJO5EE2fyfv6cNbRLsZiM+WQmqvDBst5ejaeapy86F5PdJFlX/TUgXjtuwIDAQAB"</code></pre>
650
651<h3>DMARC TXT Record</h3>
652<p>The DMARC record should be as follows:</p>
653
654<pre><code><em># Name/Host</em>
655_dmarc
656<em># Value</em>
657"v=DMARC1; p=reject; rua=mailto:dmarc@<strong>example.com</strong>; fo=1"
658</code></pre>
659
660<h3>SPF Record</h3>
661<p>Your SPF record will look like this. Remember to replace
662<strong>mail.example.com</strong> with your server name.</p>
663
664<pre><code><em># Name/Host</em>
665@
666<em># Value</em>
667"v=spf1 a:<strong>mail.example.com</strong> -all"
668</code></pre>
669
670<h3>PTR Record</h3>
671<p>Many mail servers rely on PTR records for verification purposes so we need
672to make sure our server's IP address resolves to the proper domain name. If
673your mail server is residing on a VPS, you will need to add this record on your
674VPS provider's interface, consult their documentation for details.</p>
675
676<h2>Creating your own Mail User</h2>
677<p>Your mail server is now up and running. Let's create an email for you to
678receive mail.</p>
679
680<pre><code>useradd --shell /usr/sbin/nologin --create-home --user-group <strong>user</strong>
681echo "<strong>user@example.com user</strong>" &gt;&gt; /etc/postfix/login_maps
682echo "<strong>user user</strong>" &gt;&gt; /etc/postfix/local_maps
683postmap /etc/postfix/login_maps
684postmap /etc/postfix/local_maps
685postfix reload
686</code></pre>
687
688<p>I have a script available for adding and removing users that you can find
689<a href=https://git.chudnick.com/mail-tools/tree/server/mailadm>here</a>.
690
691<h3>Connecting From a Mail Client</h3>
692<p>When connecting your account to a mail client you need to use these settings.</p>
693
694<ul>
695 <li>Username: <strong>user@example.com</strong> </li>
696
697 <li>Password: the password for <strong>user@example.com</strong> </li>
698
699 <li>Server name: <strong>mail.example.com</strong> </li>
700
701 <li>IMAP Port: 993</li>
702
703 <li>IMAP Connection: SSL/TLS</li>
704
705 <li>SMTP Port: 465</li>
706
707 <li>SMTP Connection Type: SSL/TLS</li>
708
709</ul>
710<p>
711<hr>
712Consider <a href=../donate.html>donating</a> if this article was useful.
713<a class=qr href=../images/bitcoin.png>[BTC]</a>
714</p>
715 </main>
716 <footer>
717 <a href=../kb.html>Knowledge Base</a>
718 <br>
719 <a href=../index.html>www.chudnick.com</a>
720 </footer>
721</body>
722</html>
723
diff --git a/articles/mdadm-raid.html b/articles/mdadm-raid.html
new file mode 100644
index 0000000..dd2a014
--- /dev/null
+++ b/articles/mdadm-raid.html
@@ -0,0 +1,120 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' href='../style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1>Linux Software RAID</h1></header>
12 <main>
13 <p><strong>mdadm</strong> is a tool that allows for creation and
14 management of software RAID arrays on Linux. Creating an array
15 is a rather straightforward process.</p>
16
17 <h2>Install packages</h2>
18 <p>The only package needed is mdadm itself</p>
19 <pre><code>apt install mdadm</code></pre>
20
21 <h2>Partition disks</h2>
22 <p>We'll need to parition the disks to be used in the array before
23 creating it. This isn't anything complicated, we will just be
24 creating a single partition using all the space on each disk.</p>
25
26 <p>Use <strong>lsblk</strong> to get a list of disks attached to your system.</p>
27
28 <img src=../images/raid/lsblk.png alt="lsblk command">
29
30 <p>Then use <strong>fdisk</strong> to edit the partition table of the
31 first disk. In my case this would be <strong>/dev/sdb</strong>.
32 Be sure that you are selecting the correct disk as selecting the
33 wrong one can result in data being lost.</p>
34
35 <pre><code>fdisk /dev/sdb</code></pre>
36
37 <p>Use <strong>g</strong> to create a new GUID partition table.
38 Use <strong>n</strong> to create a new partition, and then just press
39 enter at all of the prompts to accept the defaults. Finally use
40 <strong>w</strong> to write the changes. You can use lsblk again
41 to verify the change and you should see that /dev/sdb now has a
42 partition <strong>/dev/sdb1</strong>.</p>
43
44 <img src=../images/raid/fdisk.png alt="fdisk command">
45
46 <p>Repeat this process for your other disks before continuing.</p>
47
48
49 <h2>Create the array</h2>
50 <p>Creating the array is done with a single command, but takes just a
51 bit of planning.</p>
52 <ul>
53 <li>Define an ID for the array, which is just a
54 number identifier. I use <em>0</em> in the command.</li>
55 <li>Determine the RAID level you want to use. I am going to
56 use RAID5 in this example. The argument to --level is the
57 number of the RAID level</li>
58 <li>Determine the devices that will be used in the array.
59 Somewhat contrary to the argument name, these devices
60 will actually be the partitions of the disks and not the
61 disks themselves. In the command, give the number of
62 partitions (<em>3</em>) and then a space-separated list of the
63 partitions that will be active in the array
64 (<em>/dev/sdb1 /dev/sdc1 /dev/sdd1</em>).</li>
65 <li>If you want to have any spare devices in the array you
66 will define them with the --spare-devices argument. These are
67 defined in the exact same way as the active RAID devices. In
68 the example I use <em>1</em> spare <em>/dev/sde1</em>. Spare
69 devices are hot-spares that will automatically be inserted into
70 the array if one of the disks fails.</li>
71 </ul>
72
73 <pre><code>mdadm --create /dev/md<em>0</em> --level=<em>5</em> --raid-devices=<em>3</em> <em>/dev/sdb1 /dev/sdc1 /dev/sdd1</em> --spare-devices=<em>1</em> <em>/dev/sde1</em></code></pre>
74
75 <p>After creating the array run the following command to get details
76 and the status of the array. It will take a bit to initialize the
77 array, you will know this is done when the state is clean. You do not
78 need to wait for the array to completely intialize to continue.</p>
79
80 <pre><code>mdadm --detail /dev/md<em>0</em></code></pre>
81
82 <p>Take note of the UUID and name values as we will need them in the
83 next step.</p>
84
85 <p>Before moving on we need to make a filesystem on the array. I'm
86 going to make a simple EXT4 filesystem here.</p>
87
88 <pre><code>mkfs.ext4 /dev/md<em>0</em></code></pre>
89
90
91 <h2>Configuration Files</h2>
92
93 <p>Open the mdadm configuration file at
94 <strong>/etc/mdadm/mdadm.conf</strong> and append this line. Replace
95 <em>uuid</em> and <em>name</em> with the values you got when running
96 mdadm --detail, replace <em>0</em> whatever ID you chose.</p>
97
98 <pre><code>ARRAY /dev/md<em>0</em> metadata=1.2 UUID=<em>uuid</em> name=<em>name</em></code></pre>
99
100 <p>Optionally, create an <strong>/etc/fstab</strong> entry for
101 automounting of the array. Replace /mnt/raid with the directory
102 where you want to mount the array. If you made a filesystem other than
103 ext4 make sure to change that value.</p>
104
105 <pre><code>/dev/md<em>0</em> /mnt/raid ext4 defaults 0 1</code></pre>
106
107<p>
108<hr>
109Consider <a href=../donate.html>donating</a> if this article was useful.
110<a class=qr href=../images/bitcoin.png>[BTC]</a>
111</p>
112 </main>
113 <footer>
114 <a href=../kb.html>Knowledge Base</a>
115 <br>
116 <a href=../index.html>www.chudnick.com</a>
117 </footer>
118</body>
119</html>
120
diff --git a/articles/mutt.html b/articles/mutt.html
new file mode 100644
index 0000000..962ae33
--- /dev/null
+++ b/articles/mutt.html
@@ -0,0 +1,27 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' href='../style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1>Mutt - Terminal Email Client</h1></header>
12 <main>
13 </main>
14<p>
15<hr>
16Consider <a href=../donate.html>donating</a> if this article was useful.
17<a class=qr href=../images/bitcoin.png>[BTC]</a>
18</p>
19 </main>
20 <footer>
21 <a href=../kb.html>Knowledge Base</a>
22 <br>
23 <a href=../index.html>www.chudnick.com</a>
24 </footer>
25</body>
26</html>
27
diff --git a/articles/pam-tfa.html b/articles/pam-tfa.html
new file mode 100644
index 0000000..7bdc551
--- /dev/null
+++ b/articles/pam-tfa.html
@@ -0,0 +1,157 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' href='../style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1>PAM OATH Two Factor Authentication</h1></header>
12 <main>
13 <p>In this article we are going to look at configuring two factor
14 authentication via PAM using OATH. This is a simple and private way
15 to increase the security of your systems. Even if you are not familiar
16 with the term, it is likely that you
17 have used OATH before. OATH (specifically TOTP) is the rotating 6
18 digit code that you get from scanning a QR code when setting up 2FA
19 on an account.</p>
20
21 <p>This example will show how to configure 2FA for SSH logins to a
22 server, but can easily be generalized to cover other programs or
23 even all authentication on a system. The two factors here will be
24 public key authentication and then the OATH/TOTP code.
25 <em>It is highly recommended that you remain SSHd into your server
26 until after testing to avoid locking yourself out in the event
27 of a configuration error.</em></p>
28
29 <h2>Install Packages</h2>
30 <p>You only need to install a single package on the server side.</p>
31
32 <pre><code>apt install libpam-oath</code></pre>
33
34 <p>On the client machine that will be SSHing to the server install
35 these two packages.</p>
36
37 <pre><code>apt install oathtool qrencode</code></pre>
38
39 <h2>Configure OATH</h2>
40 <p>Create the OATH configuration file <strong>/etc/users.oath</strong>.
41 This file will contain the OATH secret keys so permissions need to be
42 set to only allow the root user to view it.</p>
43
44 <pre><code>touch /etc/users.oath
45chown root: /etc/users.oath
46chmod 600 /etc/users.oath</code></pre>
47
48 <p>Generate a secret key for the TOTP. Treat this secret key as you
49 would your SSH or GPG private key. Anyone who has this key will be able
50 to generate the code needed to authenticate.</p>
51
52 <pre><code>openssl rand -hex 10</code></pre>
53
54 <p>Now we define the TOTP configuration for our user. If you were
55 setting this up for multiple users you would make one entry per line.
56 Open <strong>/etc/users.oath</strong> and add this line.
57 <em>user</em> is the username of the account you will SSH into.
58 Replace the long string of numbers and letters with the secret key
59 you just generated.</p>
60
61 <pre><code>HOTP/T30/6 <em>user</em> - <em>00112233445566aabbcc</em></code></pre>
62
63
64 <h2>Configure PAM</h2>
65 <p>Now we need to tell PAM to use OATH to authenticate sshd. Do that
66 by opening <strong>/etc/pam.d/sshd</strong> and adding the following
67 line to the top of the file.</p>
68
69 <pre><code>auth sufficient pam_oath.so usersfile=/etc/users.oath window=30 digits=6</code></pre>
70
71 <p>This tells PAM to consider a valid 6 digit code as fully authenticated
72 and to skip any other processing that may normally occur, such as
73 requesting a password.</p>
74
75 <h2>Configure SSHD</h2>
76 <p>We need to make a few changes to the sshd configuration to allow
77 OATH to work properly. Open the sshd configuration file at
78 <strong>/etc/ssh/sshd_config</strong> and make the following changes.</p>
79
80 <pre><code>AuthenticationMethods publickey,keyboard-interactive
81PubkeyAuthentication yes
82PasswordAuthentication no
83ChallengeResponseAuthentication yes
84UsePAM yes</code></pre>
85
86 <p>The <strong>AuthenticationMethods</strong> line specifically tells
87 sshd that a user needs to both have an authorized SSH key and know
88 the proper 6 digit code to login.</p>
89
90 <p>Restart sshd to apply the changes</p>
91
92 <pre><code>systemctl restart sshd</code></pre>
93
94 <h2>Test the Changes</h2>
95 <p>From your client ssh into your server as normal. Instead of
96 connecting as you have been, you should now see a prompt for your
97 one time password. You can use <strong>oathtool</strong> to get
98 the code. Again, replace the long string of numbers and letters
99 with the secret key you generated on the server.</p>
100
101 <pre><code>oathtool --totp -d6 <em>00112233445566aabbcc</em></code></pre>
102
103 <p>Enter that 6 digit code into the prompt and you will be logged
104 into your server.</p>
105
106 <p>Now, in the unlikely event that your SSH private key is stolen,
107 an attacker still won't be able to access your server!</p>
108
109 <h2>Managing your TOTP</h2>
110 <p>You probably don't want to run the oathtool command everytime you
111 need your code, and while you could make an alias, that would require
112 storing your secret key in plaintext. Here are some better options.</p>
113
114 <ul>
115 <li><strong>pass otp</strong> is an extension to the command-line
116 password manager <strong>pass</strong> for handling TOTP.
117 Use this if you are already using pass</li>
118 <li><strong>KeePassXC</strong> is a graphical password
119 manager that can manage TOTP</li>
120 <li><strong>Gnome Authenticator</strong> is a graphical
121 TOTP manager for the GNOME desktop environment</li>
122 </ul>
123
124 <p>You may also want to generate a QR code for easy setup on another
125 device. Rerun the same oathtool command as before with the -v flag
126 to get the base32 version of your secret key.</p>
127
128 <pre><code>oathtool --totp -v -d6 <em>00112233445566aabbcc</em>
129--------------------------------
130Hex secret: 00112233445566aabbcc
131Base32 secret: <strong>AAISEM2EKVTKVO6M</strong>
132Digits: 6
133Window size: 0
134TOTP mode: SHA1
135Step size (seconds): 30
136</code></pre>
137
138 <p>Then use qrencode to generate the QR code image.</p>
139
140 <pre><code>qrencode -o <em>totp.png</em> 'otpauth://totp/<em>user</em>@<em>server</em>?secret=<em>AAISEM2EKVTKVO6M</em>'</code></pre>
141
142 </main>
143
144<p>
145<hr>
146Consider <a href=../donate.html>donating</a> if this article was useful.
147<a class=qr href=../images/bitcoin.png>[BTC]</a>
148</p>
149 </main>
150 <footer>
151 <a href=../kb.html>Knowledge Base</a>
152 <br>
153 <a href=../index.html>www.chudnick.com</a>
154 </footer>
155</body>
156</html>
157
diff --git a/articles/template.html b/articles/template.html
new file mode 100644
index 0000000..f908cab
--- /dev/null
+++ b/articles/template.html
@@ -0,0 +1,27 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' href='../style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1>Article</h1></header>
12 <main>
13 </main>
14<p>
15<hr>
16Consider <a href=../donate.html>donating</a> if this article was useful.
17<a class=qr href=../images/bitcoin.png>[BTC]</a>
18</p>
19 </main>
20 <footer>
21 <a href=../kb.html>Knowledge Base</a>
22 <br>
23 <a href=../index.html>www.chudnick.com</a>
24 </footer>
25</body>
26</html>
27
diff --git a/blog.html b/blog.html
new file mode 100644
index 0000000..60c43f0
--- /dev/null
+++ b/blog.html
@@ -0,0 +1,19 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title>chudnick.com - Blog</title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' type='text/css' href='style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1 class=pagetop>Blog</h1></header>
12 <main>
13 This page is reserved for blog posts. If I ever feel the need
14 to comment on something publicly, it will be placed here.
15 </main>
16 <footer><a href=index.html>www.chudnick.com</a></footer>
17</body>
18</html>
19
diff --git a/donate.html b/donate.html
new file mode 100644
index 0000000..d23b786
--- /dev/null
+++ b/donate.html
@@ -0,0 +1,22 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' type='text/css' href='style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1 class=pagetop>Donate</h1></header>
12 <main>
13 <h2 class=donate>Bitcoin</h2>
14 <p class=donate>bc1qzmpetsvyteku76cdv7qz2ngmxtxvyfuql973yd</p>
15
16 <img src=images/bitcoin.png alt="Bitcoin QR">
17 <br><br><br><br>
18 </main>
19 <footer><a href=index.html>www.chudnick.com</a></footer>
20</body>
21</html>
22
diff --git a/images/bitcoin.png b/images/bitcoin.png
new file mode 100644
index 0000000..9749835
--- /dev/null
+++ b/images/bitcoin.png
Binary files differ
diff --git a/images/desktop-720.png b/images/desktop-720.png
new file mode 100644
index 0000000..3de22d5
--- /dev/null
+++ b/images/desktop-720.png
Binary files differ
diff --git a/images/desktop.png b/images/desktop.png
new file mode 100644
index 0000000..bd0ae44
--- /dev/null
+++ b/images/desktop.png
Binary files differ
diff --git a/images/director/debian-template.png b/images/director/debian-template.png
new file mode 100644
index 0000000..9c64c0f
--- /dev/null
+++ b/images/director/debian-template.png
Binary files differ
diff --git a/images/director/director.png b/images/director/director.png
new file mode 100644
index 0000000..02f7b8f
--- /dev/null
+++ b/images/director/director.png
Binary files differ
diff --git a/images/director/host-services.png b/images/director/host-services.png
new file mode 100644
index 0000000..6f02306
--- /dev/null
+++ b/images/director/host-services.png
Binary files differ
diff --git a/images/director/hosttemplate.png b/images/director/hosttemplate.png
new file mode 100644
index 0000000..294978a
--- /dev/null
+++ b/images/director/hosttemplate.png
Binary files differ
diff --git a/images/director/linux-template.png b/images/director/linux-template.png
new file mode 100644
index 0000000..eb881b3
--- /dev/null
+++ b/images/director/linux-template.png
Binary files differ
diff --git a/images/director/service-set.png b/images/director/service-set.png
new file mode 100644
index 0000000..1447273
--- /dev/null
+++ b/images/director/service-set.png
Binary files differ
diff --git a/images/director/service-template.png b/images/director/service-template.png
new file mode 100644
index 0000000..b5cdc1e
--- /dev/null
+++ b/images/director/service-template.png
Binary files differ
diff --git a/images/director/templates.png b/images/director/templates.png
new file mode 100644
index 0000000..444aaaf
--- /dev/null
+++ b/images/director/templates.png
Binary files differ
diff --git a/images/freeipa-webui.png b/images/freeipa-webui.png
new file mode 100644
index 0000000..c7ec465
--- /dev/null
+++ b/images/freeipa-webui.png
Binary files differ
diff --git a/images/git.svg b/images/git.svg
new file mode 100644
index 0000000..a725b01
--- /dev/null
+++ b/images/git.svg
@@ -0,0 +1,15 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5 width="42px" height="42px" viewBox="0 0 97 97" enable-background="new 0 0 97 97" xml:space="preserve">
6<g>
7 <path fill="#F05133" d="M92.71,44.408L52.591,4.291c-2.31-2.311-6.057-2.311-8.369,0l-8.33,8.332L46.459,23.19
8 c2.456-0.83,5.272-0.273,7.229,1.685c1.969,1.97,2.521,4.81,1.67,7.275l10.186,10.185c2.465-0.85,5.307-0.3,7.275,1.671
9 c2.75,2.75,2.75,7.206,0,9.958c-2.752,2.751-7.208,2.751-9.961,0c-2.068-2.07-2.58-5.11-1.531-7.658l-9.5-9.499v24.997
10 c0.67,0.332,1.303,0.774,1.861,1.332c2.75,2.75,2.75,7.206,0,9.959c-2.75,2.749-7.209,2.749-9.957,0c-2.75-2.754-2.75-7.21,0-9.959
11 c0.68-0.679,1.467-1.193,2.307-1.537V36.369c-0.84-0.344-1.625-0.853-2.307-1.537c-2.083-2.082-2.584-5.14-1.516-7.698
12 L31.798,16.715L4.288,44.222c-2.311,2.313-2.311,6.06,0,8.371l40.121,40.118c2.31,2.311,6.056,2.311,8.369,0L92.71,52.779
13 C95.021,50.468,95.021,46.719,92.71,44.408z"/>
14</g>
15</svg>
diff --git a/images/icinga-login.png b/images/icinga-login.png
new file mode 100644
index 0000000..51792c0
--- /dev/null
+++ b/images/icinga-login.png
Binary files differ
diff --git a/images/raid/fdisk.png b/images/raid/fdisk.png
new file mode 100644
index 0000000..18d2697
--- /dev/null
+++ b/images/raid/fdisk.png
Binary files differ
diff --git a/images/raid/lsblk.png b/images/raid/lsblk.png
new file mode 100644
index 0000000..a748541
--- /dev/null
+++ b/images/raid/lsblk.png
Binary files differ
diff --git a/images/rss.svg b/images/rss.svg
new file mode 100644
index 0000000..5f6acb2
--- /dev/null
+++ b/images/rss.svg
@@ -0,0 +1,33 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4<svg version="1.1" id="svg2" sodipodi:version="0.32" inkscape:version="0.47 r22583" inkscape:output_extension="org.inkscape.output.svg.inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" sodipodi:docname="rss-feed.svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="42px" height="42px" viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve">
5<path fill="#E15A00" d="M9.496,210.008c0,19.6,15.888,35.486,35.486,35.486h164.034c19.604,0,35.487-15.889,37.487-34.82 l-0.001-164.013c-1.999-20.266-17.888-36.155-37.484-36.155H44.982c-19.599,0-35.486,15.889-35.486,35.487V210.008z"/>
6<g id="layer1" transform="translate(-373.642,-318.344)" inkscape:groupmode="layer" inkscape:label="Layer 1">
7
8 <path id="path5270" sodipodi:cy="200.64285" sodipodi:type="arc" sodipodi:cx="360.35715" sodipodi:rx="24.642859" sodipodi:ry="23.928572" fill="#FFFFFF" d=" M469.09,505.078c0,11.498-9.598,20.817-21.438,20.817c-11.84,0-21.438-9.319-21.438-20.817c0-11.496,9.599-20.816,21.438-20.816 C459.491,484.262,469.09,493.582,469.09,505.078z"/>
9 <path id="path5805" sodipodi:nodetypes="ccccc" fill="#FFFFFF" d="M426.835,455.057l-0.073-30.273 c64.706,3.375,100.618,49.674,101.5,101.939h-30.318C497.441,480.781,466.204,456.728,426.835,455.057z"/>
10 <path id="path5807" sodipodi:nodetypes="ccccc" fill="#FFFFFF" d="M427.202,404.572l-0.879-30.758 c99.428,4.616,152.676,76.769,153.348,152.909l-31.197-0.439C549.839,477.58,513.808,406.017,427.202,404.572z"/>
11</g>
12<g>
13
14 <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="102.5" y1="-491.002" x2="102.5" y2="-598.5135" gradientTransform="matrix(1 0 0 -1 25.5 -353)">
15 <stop offset="0" style="stop-color:#000000;stop-opacity:0.15"/>
16 <stop offset="0.6626" style="stop-color:#000000;stop-opacity:0"/>
17 </linearGradient>
18 <path fill="url(#SVGID_1_)" d="M9.496,115.402v94.606c0,19.6,15.888,35.486,35.487,35.486h164.033 c19.604,0,35.488-15.889,37.488-34.82v-95.952c-36.779,15.182-77.074,23.577-119.337,23.577 C85.542,138.299,45.825,130.154,9.496,115.402z"/>
19</g>
20<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="102.4995" y1="-364.168" x2="102.4995" y2="-491.7969" gradientTransform="matrix(1 0 0 -1 25.5 -353)">
21 <stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.85"/>
22 <stop offset="0.66" style="stop-color:#FFFFFF;stop-opacity:0"/>
23</linearGradient>
24<path fill="url(#SVGID_2_)" d="M209.018,10.505H44.983c-19.599,0-35.487,15.889-35.487,35.487v69.409 c36.33,14.751,76.046,22.897,117.671,22.897c42.263,0,82.558-8.396,119.336-23.577v-68.06 C244.504,26.395,228.615,10.505,209.018,10.505z"/>
25<path fill="none" stroke="#E15A00" stroke-width="2" stroke-miterlimit="10" d="M246.503,114.721V46.66 c-1.999-20.266-17.888-36.155-37.485-36.155H44.982c-19.599,0-35.486,15.889-35.486,35.487v69.409"/>
26<g>
27 <g>
28 <g>
29 <path fill="none" stroke="#B34700" stroke-width="2" stroke-miterlimit="10" d="M9.496,115.401v94.605 c0,19.6,15.888,35.486,35.486,35.486h164.034c19.604,0,35.487-15.889,37.487-34.819v-95.952"/>
30 </g>
31 </g>
32</g>
33</svg>
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..fbd88f3
--- /dev/null
+++ b/index.html
@@ -0,0 +1,31 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title>chudnick.com</title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' type='text/css' href='style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1 class=pagetop>Welcome</h1></header>
12 <main>
13 <div class="quicklinks">
14 <a class=quicklinks href=https://git.chudnick.com><img class=ql src=images/git.svg></a>
15 <a class=quicklinks href=rss.xml><img class=ql src=images/rss.svg></a>
16 </div>
17 <div class="sidebar">
18 <ul>
19 <li class=sidebar><a class=sidebar href=blog.html>Blog</a></li>
20 <li class=sidebar><a class=sidebar href=software.html>Software</a></li>
21 <li class=sidebar><a class=sidebar href=kb.html>Knowledge Base</a></li>
22 <li class=sidebar><a class=sidebar href=projects.html>Projects</a></li>
23 <li class=sidebar><a class=sidebar href=about-me.html>About Me</a></li>
24 <li class=sidebar><a class=sidebar href=donate.html>Donate</a></li>
25 <ul>
26 </div>
27 </main>
28 <!-- <footer><a href=index.html>www.chudnick.com</a></footer> -->
29</body>
30</html>
31
diff --git a/kb.html b/kb.html
new file mode 100644
index 0000000..37bf647
--- /dev/null
+++ b/kb.html
@@ -0,0 +1,82 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title>chudnick.com - Knowledge Base</title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' type='text/css' href='style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1 class=pagetop>Knowledge Base</h1></header>
12 <main>
13 <p>This page contains various articles on technology topics of interest,
14 typically structured as how-to or tutorial documents.
15 Items without links indicate future topics I intend to cover. All articles
16 are intended for Debian 11 unless otherwise stated, but should be similar
17 if tried on other distros.</p>
18 <h2>Configuration Management</h2>
19 <ul>
20 <li>Ansible Basics</li>
21 <li>Ansible Playbooks</li>
22 <li>Ansible integration with FreeIPA</li>
23 </ul>
24
25 <h2>Desktop Programs</h2>
26 <ul>
27 <li><a href=articles/mutt.html>Mutt - Terminal Email Client</a></li>
28 </ul>
29
30 <h2>Identity Management</h2>
31 <ul>
32 <li><a href=articles/freeipa-server.html>FreeIPA Server Setup</a></li>
33 <li>Integrated 2FA with FreeIPA</li>
34 <li>FreeIPA Sudo Rules</li>
35 <li>Kerberized NFS using FreeIPA</li>
36 </ul>
37
38 <h2>Miscellaneous</h2>
39 <ul>
40 <a href=articles/mdadm-raid.html><li>Linux Software RAID</li></a>
41 <li>Debian Archive Mirror</li>
42 </ul>
43
44 <h2>Monitoring</h2>
45 <ul>
46 <li><a class=kbitem href=articles/icinga-master.html>Icinga2 Master Installation</a></li>
47 <li><a class=kbitem href=articles/icinga-director.html>Icinga2 Director</a></li>
48 <li><a class=kbitem href=articles/icinga-agent.html>Icinga2 Agent Installation and Configuration</a></li>
49 <li><a href=articles/icinga-influx.html>Store Icinga2 data in InfluxDB</a></li>
50 <li>Graph Icinga data with Grafana and InfluxDB</li>
51 <li>Icinga2 Alert Notifications</li>
52 </ul>
53
54 <h2>Networking</h2>
55 <ul>
56 <li>BIND9 DNS Server</li>
57 <li>ISC DHCP Server</li>
58 <li>Chrony NTP Server</li>
59 <li>UFW Host-Based Firewall</li>
60 </ul>
61
62 <h2>Security</h2>
63 <ul>
64 <li><a href=articles/pam-tfa.html>PAM OATH Two Factor Authentication</a></li>
65 <li><a href=articles/luks.html>LUKS Device Encryption</a></li>
66 <li>Prelude SIEM</li>
67 <li>Snort IPS</li>
68 <li>FreeRADIUS Server</li>
69 </ul>
70
71 <h2>Self Hosting</h2>
72 <ul>
73 <li><a class=kbitem href=articles/mail-server.html>Postfix/Dovecot Mail Server</a></li>
74 <li>Jellyfin Media Server</li>
75 <li>Searx Self-Hosted Search Engine</li>
76 <li>Proxmox Virtual Environment</li>
77
78 </ul>
79 </main>
80 <footer><a href=index.html>www.chudnick.com</a></footer>
81</body>
82</html>
diff --git a/projects.html b/projects.html
new file mode 100644
index 0000000..d6a2f5c
--- /dev/null
+++ b/projects.html
@@ -0,0 +1,22 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' type='text/css' href='style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1 class=pagetop>Projects</h1></header>
12 <main>
13 <h2><a href=projects/mfa.html>mfa</a></h2>
14 <h2>clibrary</h2>
15 <h2>mail-tools</h2>
16 <h2>deploy-scripts</h2>
17 <h2>server-scripts</h2>
18 </main>
19 <footer><a href=index.html>www.chudnick.com</a></footer>
20</body>
21</html>
22
diff --git a/projects/mfa.html b/projects/mfa.html
new file mode 100644
index 0000000..2a89856
--- /dev/null
+++ b/projects/mfa.html
@@ -0,0 +1,150 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' type='text/css' href='style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1 class=pagetop>Projects</h1></header>
12 <main>
13 <h2>mfa</h2>
14 <p><em>Check out the source code here - </em>
15 <a href=https://git.chudnick.com/mfa>git.chudnick.com/mfa</a></p>
16
17 <p><strong>mfa</strong> is a system for out-of-band multi-factor
18 authentication with PAM.
19 My original reason for working on this was to get MFA functionality for
20 a Postfix/Dovecot mail server that uses PAM for authentication.
21 Solutions such as pam_oath are not feasible
22 for this purpose because a mail client has no way of exposing an
23 interface for the oath challenge-response.
24 Therefore a way to circumvent the original application to get the request
25 to the user is needed, which is what mfa does.</p>
26
27 <p>The design of mfa is not novel, it works the same way as Cisco's Duo.
28 Duo does have open source modules for achieving this objective, but all
29 the authentication requests are
30 sent back to their proprietary "cloud" service. I'm sure that most
31 free software
32 enthusiasts see this as a major red flag, especially for small personal
33 use cases.</p>
34
35 <h3>Design</h3>
36
37 <p>mfa is primarily composed of three parts - the server, the client,
38 and the PAM module.
39 The server listens for connections from both clients and PAM
40 modules. The server receives a
41 request from a PAM module that includes the username of the user
42 attempting to authenticate,
43 the hostname of the computer, and the service being accessed. The
44 server then correlates the
45 combination of user, host, and service to a particular client, and
46 attempts to push a request.
47 The server will then evaluate the client's response, and either
48 return to the PAM module that
49 the user is authenticated or denied.</p>
50
51 <p>The server itself consists of two parts that I've called
52 <strong>mfad</strong> and
53 <strong>mfac</strong>. mfad is the program responsible for doing
54 what I've described above.
55 mfac is a command line utility that the administrator uses to
56 configure the server. mfac is used
57 to enroll clients in the system and to provision applications. A
58 client is enrolled by using the
59 --add-client option and providing an alias for that user. The
60 server then assigns that user an
61 identifying key that is used to connect and a TOTP secret key. With
62 the client enrolled, the
63 administrator can then assign applications to that client. With the
64 --add-app command, the
65 administrator ties a username, hostname, and service combination to
66 a client alias, so that
67 when that combination is seen the server knows who to ask for
68 authentication. The administrator
69 also identifies which MFA methods are valid for this combination
70 (currently either or both of
71 push and/or totp). The example below shows the process of
72 enrolling a new client called
73 'tux' and then provisioning MFA for SSH attempts to
74 tux@linux.example.org.</p>
75
76 <pre><code><em># Enroll a client named tux</em>
77mfac --add-client tux
78alias: tux
79client key: VA32LB3SF2HG2FDWJS5XIOFVWTMBQYRSQ3PK3OOPA3FBIQMSMJZCXYJQCYKYUWUU
80totp secret: TGGG3QCXA4MR2S2X6B33GSYN
81uri: otpauth://totp/tux%40mfad?secret=TGGG3QCXA4MR2S2X6B33GSYN
82
83<em># Provision MFA for SSH tux@linux.example.org allowing for both push
84authentication or TOTP</em>
85mfac --add-app --user tux --host linux.example.org --service sshd --alias tux
86--methods push totp
87 </code></pre>
88
89 <p>The PAM module of mfa also consists of two parts: the actual PAM
90 module
91 <strong>pam_mfa.so</strong> that gets called in the PAM stack and a
92 helper
93 program that interacts with mfad. The job of pam_mfa.so is to
94 retrieve the
95 necessary information (user and service) from PAM and then invoke
96 the helper
97 program with that data. It then waits for the MFA process to
98 complete, retrieves
99 the result, and returns either success or failure to the PAM stack.
100 The helper
101 program initiates a connetion to mfad when run and then passes
102 username, hostname,
103 and service information to the server. It too receives a success
104 or failure response
105 and then relays that information to the PAM module. Here is an
106 example of using
107 pam_mfa.so in the PAM stack for sshd.</p>
108
109 <pre><code><strong>/etc/pam.d/sshd</strong>
110auth requisite pam_mfa.so</code></pre>
111
112 <p>The client program is what the end user interacts with to
113 provide authentication responses.
114 Currently it is only a very simple terminal program but expanding
115 on this is high on the
116 TODO list. The client opens a connection to the server and
117 identifies itself with the client
118 key that was generated during enrollment. The client waits for a
119 prompt from the server, and
120 when it receives one, informs the user. The client receives the
121 users input and sends it back
122 to the server. The client performs this loop continuously until it
123 is closed.</p>
124
125 <h2>clibrary</h2>
126
127 <p><em>Check out the source code here -</em>
128 <a href=https://git.chudnick.com/clibrary>git.chudnick.com/clibrary</a></p>
129
130 <h2>mail-tools</h2>
131 <p>
132 <a href=https://git.chudnick.com/mail-tools>git.chudnick.com/mail-tools</a>
133 </p>
134
135 <h2>deploy-scripts</h2>
136 <p>
137 <a href=https://git.chudnick.com/deploy-scripts>
138 git.chudnick.com/deploy-scripts</a>
139 </p>
140
141 <h2>server-scripts</h2>
142 <p>
143 <a href=https://git.chudnick.com/server-scripts>
144 git.chudnick.com/server-scripts</a>
145 </p>
146 </main>
147 <footer><a href=index.html>www.chudnick.com</a></footer>
148</body>
149</html>
150
diff --git a/projects/template.html b/projects/template.html
new file mode 100644
index 0000000..77b6c6a
--- /dev/null
+++ b/projects/template.html
@@ -0,0 +1,107 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' type='text/css' href='style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1 class=pagetop>Projects</h1></header>
12 <main>
13 <h2>mfa</h2>
14 <p><em>Check out the source code here - </em>
15 <a href=https://git.chudnick.com/mfa>git.chudnick.com/mfa</a></p>
16
17 <p><strong>mfa</strong> is a system for out-of-band multi-factor authentication with PAM.
18 My original reason for working on this was to get MFA functionality for a Postfix/Dovecot
19 mail server that uses PAM for authentication. Solutions such as pam_oath are not feasible
20 for this purpose because a mail client has no way of exposing an interface for the oath
21 challenge-response. Therefore a way to circumvent the original application to get the request
22 to the user is needed, which is what mfa does.</p>
23
24 <p>The design of mfa is not novel, it works the same way as Cisco's Duo. Duo does have open
25 source modules for achieving this objective, but all the authentication requests are
26 sent back to their proprietary "cloud" service. I'm sure that most free software
27 enthusiasts see this as a major red flag, especially for small personal use cases.</p>
28
29 <h3>Design</h3>
30
31 <p>mfa is primarily composed of three parts - the server, the client, and the PAM module.
32 The server listens for connections from both clients and PAM modules. The server receives a
33 request from a PAM module that includes the username of the user attempting to authenticate,
34 the hostname of the computer, and the service being accessed. The server then correlates the
35 combination of user, host, and service to a particular client, and attempts to push a request.
36 The server will then evaluate the client's response, and either return to the PAM module that
37 the user is authenticated or denied.</p>
38
39 <p>The server itself consists of two parts that I've called <strong>mfad</strong> and
40 <strong>mfac</strong>. mfad is the program responsible for doing what I've described above.
41 mfac is a command line utility that the administrator uses to configure the server. mfac is used
42 to enroll clients in the system and to provision applications. A client is enrolled by using the
43 --add-client option and providing an alias for that user. The server then assigns that user an
44 identifying key that is used to connect and a TOTP secret key. With the client enrolled, the
45 administrator can then assign applications to that client. With the --add-app command, the
46 administrator ties a username, hostname, and service combination to a client alias, so that
47 when that combination is seen the server knows who to ask for authentication. The administrator
48 also identifies which MFA methods are valid for this combination (currently either or both of
49 push and/or totp). The example below shows the process of enrolling a new client called
50 'tux' and then provisioning MFA for SSH attempts to tux@linux.example.org.</p>
51
52 <pre><code><em># Enroll a client named tux</em>
53mfac --add-client tux
54alias: tux
55client key: VA32LB3SF2HG2FDWJS5XIOFVWTMBQYRSQ3PK3OOPA3FBIQMSMJZCXYJQCYKYUWUU
56totp secret: TGGG3QCXA4MR2S2X6B33GSYN
57uri: otpauth://totp/tux%40mfad?secret=TGGG3QCXA4MR2S2X6B33GSYN
58
59<em># Provision MFA for SSH tux@linux.example.org allowing for both push authentication or TOTP</em>
60mfac --add-app --user tux --host linux.example.org --service sshd --alias tux --methods push totp
61 </code></pre>
62
63 <p>The PAM module of mfa also consists of two parts: the actual PAM module
64 <strong>pam_mfa.so</strong> that gets called in the PAM stack and a helper
65 program that interacts with mfad. The job of pam_mfa.so is to retrieve the
66 necessary information (user and service) from PAM and then invoke the helper
67 program with that data. It then waits for the MFA process to complete, retrieves
68 the result, and returns either success or failure to the PAM stack. The helper
69 program initiates a connetion to mfad when run and then passes username, hostname,
70 and service information to the server. It too receives a success or failure response
71 and then relays that information to the PAM module. Here is an example of using
72 pam_mfa.so in the PAM stack for sshd.</p>
73
74 <pre><code><strong>/etc/pam.d/sshd</strong>
75auth requisite pam_mfa.so</code></pre>
76
77 <p>The client program is what the end user interacts with to provide authentication responses.
78 Currently it is only a very simple terminal program but expanding on this is high on the
79 TODO list. The client opens a connection to the server and identifies itself with the client
80 key that was generated during enrollment. The client waits for a prompt from the server, and
81 when it receives one, informs the user. The client receives the users input and sends it back
82 to the server. The client performs this loop continuously until it is closed.</p>
83
84 <h2>clibrary</h2>
85
86 <p><em>Check out the source code here -</em>
87 <a href=https://git.chudnick.com/clibrary>git.chudnick.com/clibrary</a></p>
88
89 <h2>mail-tools</h2>
90 <p>
91 <a href=https://git.chudnick.com/mail-tools>git.chudnick.com/mail-tools</a>
92 </p>
93
94 <h2>deploy-scripts</h2>
95 <p>
96 <a href=https://git.chudnick.com/deploy-scripts>git.chudnick.com/deploy-scripts</a>
97 </p>
98
99 <h2>server-scripts</h2>
100 <p>
101 <a href=https://git.chudnick.com/server-scripts>git.chudnick.com/server-scripts</a>
102 </p>
103 </main>
104 <footer><a href=index.html>www.chudnick.com</a></footer>
105</body>
106</html>
107
diff --git a/rss.xml b/rss.xml
new file mode 100644
index 0000000..430fecc
--- /dev/null
+++ b/rss.xml
@@ -0,0 +1,2020 @@
1<rss version="2.0">
2 <channel>
3 <title>chudnick.com</title>
4 <description>chudnick.com</description>
5 <language>en-us</language>
6 <link>https://chudnick.com/rss.xml</link>
7 <item>
8 <title>LUKS Block Device Encryption</title>
9 <guid>https://www.chudnick.com/articles/luks.html</guid>
10 <link>https://www.chudnick.com/articles/luks.html</link>
11 <pubDate>Sat, 18 Jun 2022 15:46:21 -0400</pubDate>
12 <description><![CDATA[<!DOCTYPE html>
13<html lang=en>
14 <head>
15 <title></title>
16 <meta charset="utf-8"/>
17 <link rel="shortcut icon" href="favicon.ico"/>
18 <link rel='stylesheet' href='../style.css'/>
19 <meta name="viewport" content="width=device-width, initial-scale=1">
20 </head>
21<body>
22 <header><h1>LUKS Block Device Encryption</h1></header>
23 <main>
24 <p>Linux Unified Key Setup (LUKS) is a method for encrypting
25 block devices that is built-in to the Linux Kernel. In this tutorial
26 I will be showing how to create an encrypted USB drive with LUKS, but
27 this process is applicable to other types of storage.
28 <strong>This process will wipe all data on the device that you
29 encrypt so make backups beforehand if needed</strong>.</p>
30
31 <h2>Install Packages</h2>
32 <p>Install cryptsetup and its dependencies</p>
33
34 <pre><code>apt install cryptsetup</code></pre>
35
36 <h2>Prepare the Drive</h2>
37 <p>If the device you are encrypting was previously used, you will
38 want to completely overwrite any data on it before encryption. This
39 can be done using <strong>dd</strong> as shown below. This could take
40 a very long time depending on the size and type of your drive.
41 Be sure that you enter the correct path to your drive as the
42 argument to <strong>of</strong>, and do not specify a partition:
43 <strong>/dev/sdb</strong> is correct, <strong>/dev/sdb1</strong> is
44 wrong. Obviously this will destroy any data on the device so be
45 absolutely sure you specify the correct device in the command
46 and have backups of data previously stored if needed.</p>
47
48 <pre><code>dd if=/dev/zero of=<em>/dev/sdX</em> status=progress</code></pre>
49
50 <h2>Encrypt the Drive</h2>
51 <p><strong>cryptsetup</strong> is the main command used to perform
52 LUKS-related tasks. This main command is followed by a subcommand
53 that specifies which action to perform. To create a LUKS partition
54 on a drive we need to use the subcommand <strong>luksFormat</strong>.
55 We also use the type option to explicitly say to use LUKS version 2
56 encryption. Run the command and then enter and confirm the
57 encryption password.</p>
58
59 <pre><code>cryptsetup --type luks2 luksFormat <em>/dev/sdX</em></code></pre>
60
61 <p>Now we need to open and map the encrypted LUKS device. This is done
62 by using the <strong>luksOpen</strong> subcommand. This subcommand takes
63 the device as the first argument and then a map target as the second. The
64 map target can be any string as long as a map does not already exist with
65 that name. In the example I will use <em>crypt</em>.
66
67 <pre><code>cryptsetup luksOpen <em>/dev/sdX crypt</em></code></pre>
68
69 <p>And then we just need to create a filesystem on the device; I will
70 be making an ext4 filesystem in the example. To
71 interact with an encrypted drive after it has been opened you need
72 to refer to its device mapper target, which is found under /dev/mapper.
73 Since we used <em>crypt</em> as the map target, our encrypted drive
74 is /dev/mapper/<em>crypt</em>. </p>
75
76 <pre><code>mkfs.ext4 /dev/mapper/<em>crypt</em></code></pre>
77
78 <p>After creating the filesystem created the encrypted drive
79 can now be mounted and used like any other device. Remember that
80 when mounting the device you refer to the device mapper target
81 (mount /dev/mapper/<em>crypt</em> /mnt/crypt).</p>
82
83 <p>In addition to unmounting the filesystem you should always close
84 the device mapping before removing your encrypted drive. This is
85 done with the <strong>luksClose</strong> subcommand and takes
86 the device mapping as the argument.</p>
87
88 <pre><code>cryptsetup luksClose /dev/mapper/<em>crypt</em></code></pre>
89
90 <h2>The LUKS Header</h2>
91 <p>The LUKS header sits at the front of your encrypted drive and is
92 responsible for managing access to the device. If the header is
93 damaged accessing your encrypted data will not be possible. Because of
94 this, you may want to make backups of the header, but before doing so
95 you need to weigh the risks and benefits.</p>
96
97 <p>The obvious benefit is that
98 in the event of damage to the LUKS header, you can easily restore a
99 backup and regain access to the data. However, having a backup of the
100 header makes it harder to wipe the LUKS device. Without a header
101 backup, overwriting the LUKS header on the device is enough to securely
102 wipe the drive. With backups, you need to either destroy all header
103 backups or overwrite all encrypted data on the device. The other main risk
104 is that an encryption password that is valid at the time you make a
105 backup will always be valid for that backup. For example, say you change
106 the encryption password on your device after making a backup because it
107 has been compromised. An attacker would be able to restore the header
108 backup and then use the compromised password to access the data.</p>
109
110 <p>The cryptsetup documentation refers to creating header backups
111 as making a trade-off between safety and security. You need to make a
112 decision based on your individual use-case. It's a good idea to
113 routinely update your header backups if you do choose to make them</p>
114
115 <p>When creating or restoring a header backup you always refer to the
116 block device in the command, not the device mapper taget. To create
117 a header backup:</p>
118
119 <pre><code>cryptsetup luksHeaderBackup <em>/dev/sdX</em> --header-backup-file <em>path/to/backup</em></code></pre>
120
121 <p>To restore a header from a backup:</p>
122
123 <pre><code>cryptsetup luksHeaderRestore <em>/dev/sdX</em> --header-backup-file <em>path/to/backup</em></code></pre>
124
125 <p>Note that is not necessary to store header backups on an encrypted
126 device. I would recommend storing backups on at least one non-encrypted
127 drive in case of an emergency.</p>
128
129 </main>
130<p>
131<hr>
132Consider <a href=../donate.html>donating</a> if this article was useful.
133<a class=qr href=../images/bitcoin.png>[BTC]</a>
134</p>
135 </main>
136 <footer>
137 <a href=../kb.html>Knowledge Base</a>
138 <br>
139 <a href=../index.html>www.chudnick.com</a>
140 </footer>
141</body>
142</html>]]></description>
143 </item>
144 <item>
145 <title>PAM OATH Two Factor Authentication</title>
146 <guid>https://www.chudnick.com/articles/pam-tfa.html</guid>
147 <link>https://www.chudnick.com/articles/pam-tfa.html</link>
148 <pubDate>Sat, 18 Jun 2022 15:45:01 -0400</pubDate>
149 <description><![CDATA[<!DOCTYPE html>
150<html lang=en>
151 <head>
152 <title></title>
153 <meta charset="utf-8"/>
154 <link rel="shortcut icon" href="favicon.ico"/>
155 <link rel='stylesheet' href='../style.css'/>
156 <meta name="viewport" content="width=device-width, initial-scale=1">
157 </head>
158<body>
159 <header><h1>PAM OATH Two Factor Authentication</h1></header>
160 <main>
161 <p>In this article we are going to look at configuring two factor
162 authentication via PAM using OATH. This is a simple and private way
163 to increase the security of your systems. Even if you are not familiar
164 with the term, it is likely that you
165 have used OATH before. OATH (specifically TOTP) is the rotating 6
166 digit code that you get from scanning a QR code when setting up 2FA
167 on an account.</p>
168
169 <p>This example will show how to configure 2FA for SSH logins to a
170 server, but can easily be generalized to cover other programs or
171 even all authentication on a system. The two factors here will be
172 public key authentication and then the OATH/TOTP code.
173 <em>It is highly recommended that you remain SSHd into your server
174 until after testing to avoid locking yourself out in the event
175 of a configuration error.</em></p>
176
177 <h2>Install Packages</h2>
178 <p>You only need to install a single package on the server side.</p>
179
180 <pre><code>apt install libpam-oath</code></pre>
181
182 <p>On the client machine that will be SSHing to the server install
183 these two packages.</p>
184
185 <pre><code>apt install oathtool qrencode</code></pre>
186
187 <h2>Configure OATH</h2>
188 <p>Create the OATH configuration file <strong>/etc/users.oath</strong>.
189 This file will contain the OATH secret keys so permissions need to be
190 set to only allow the root user to view it.</p>
191
192 <pre><code>touch /etc/users.oath
193chown root: /etc/users.oath
194chmod 600 /etc/users.oath</code></pre>
195
196 <p>Generate a secret key for the TOTP. Treat this secret key as you
197 would your SSH or GPG private key. Anyone who has this key will be able
198 to generate the code needed to authenticate.</p>
199
200 <pre><code>openssl rand -hex 10</code></pre>
201
202 <p>Now we define the TOTP configuration for our user. If you were
203 setting this up for multiple users you would make one entry per line.
204 Open <strong>/etc/users.oath</strong> and add this line.
205 <em>user</em> is the username of the account you will SSH into.
206 Replace the long string of numbers and letters with the secret key
207 you just generated.</p>
208
209 <pre><code>HOTP/T30/6 <em>user</em> - <em>00112233445566aabbcc</em></code></pre>
210
211
212 <h2>Configure PAM</h2>
213 <p>Now we need to tell PAM to use OATH to authenticate sshd. Do that
214 by opening <strong>/etc/pam.d/sshd</strong> and adding the following
215 line to the top of the file.</p>
216
217 <pre><code>auth sufficient pam_oath.so usersfile=/etc/users.oath window=30 digits=6</code></pre>
218
219 <p>This tells PAM to consider a valid 6 digit code as fully authenticated
220 and to skip any other processing that may normally occur, such as
221 requesting a password.</p>
222
223 <h2>Configure SSHD</h2>
224 <p>We need to make a few changes to the sshd configuration to allow
225 OATH to work properly. Open the sshd configuration file at
226 <strong>/etc/ssh/sshd_config</strong> and make the following changes.</p>
227
228 <pre><code>AuthenticationMethods publickey,keyboard-interactive
229PubkeyAuthentication yes
230PasswordAuthentication no
231ChallengeResponseAuthentication yes
232UsePAM yes</code></pre>
233
234 <p>The <strong>AuthenticationMethods</strong> line specifically tells
235 sshd that a user needs to both have an authorized SSH key and know
236 the proper 6 digit code to login.</p>
237
238 <p>Restart sshd to apply the changes</p>
239
240 <pre><code>systemctl restart sshd</code></pre>
241
242 <h2>Test the Changes</h2>
243 <p>From your client ssh into your server as normal. Instead of
244 connecting as you have been, you should now see a prompt for your
245 one time password. You can use <strong>oathtool</strong> to get
246 the code. Again, replace the long string of numbers and letters
247 with the secret key you generated on the server.</p>
248
249 <pre><code>oathtool --totp -d6 <em>00112233445566aabbcc</em></code></pre>
250
251 <p>Enter that 6 digit code into the prompt and you will be logged
252 into your server.</p>
253
254 <p>Now, in the unlikely event that your SSH private key is stolen,
255 an attacker still won't be able to access your server!</p>
256
257 <h2>Managing your TOTP</h2>
258 <p>You probably don't want to run the oathtool command everytime you
259 need your code, and while you could make an alias, that would require
260 storing your secret key in plaintext. Here are some better options.</p>
261
262 <ul>
263 <li><strong>pass otp</strong> is an extension to the command-line
264 password manager <strong>pass</strong> for handling TOTP.
265 Use this if you are already using pass</li>
266 <li><strong>KeePassXC</strong> is a graphical password
267 manager that can manage TOTP</li>
268 <li><strong>Gnome Authenticator</strong> is a graphical
269 TOTP manager for the GNOME desktop environment</li>
270 </ul>
271
272 <p>You may also want to generate a QR code for easy setup on another
273 device. Rerun the same oathtool command as before with the -v flag
274 to get the base32 version of your secret key.</p>
275
276 <pre><code>oathtool --totp -v -d6 <em>00112233445566aabbcc</em>
277--------------------------------
278Hex secret: 00112233445566aabbcc
279Base32 secret: <strong>AAISEM2EKVTKVO6M</strong>
280Digits: 6
281Window size: 0
282TOTP mode: SHA1
283Step size (seconds): 30
284</code></pre>
285
286 <p>Then use qrencode to generate the QR code image.</p>
287
288 <pre><code>qrencode -o <em>totp.png</em> 'otpauth://totp/<em>user</em>@<em>server</em>?secret=<em>AAISEM2EKVTKVO6M</em>'</code></pre>
289
290 </main>
291
292<p>
293<hr>
294Consider <a href=../donate.html>donating</a> if this article was useful.
295<a class=qr href=../images/bitcoin.png>[BTC]</a>
296</p>
297 </main>
298 <footer>
299 <a href=../kb.html>Knowledge Base</a>
300 <br>
301 <a href=../index.html>www.chudnick.com</a>
302 </footer>
303</body>
304</html>]]></description>
305 </item>
306 <item>
307 <title>FreeIPA Server Setup</title>
308 <guid>https://www.chudnick.com/articles/freeipa-server.html</guid>
309 <link>https://www.chudnick.com/articles/freeipa-server.html</link>
310 <pubDate>Sat, 18 Jun 2022 15:44:21 -0400</pubDate>
311 <description><![CDATA[<!DOCTYPE html>
312<html lang=en>
313 <head>
314 <title></title>
315 <meta charset="utf-8"/>
316 <link rel="shortcut icon" href="favicon.ico"/>
317 <link rel='stylesheet' href='../style.css'/>
318 <meta name="viewport" content="width=device-width, initial-scale=1">
319 </head>
320<body>
321 <header><h1>FreeIPA Server Setup</h1></header>
322 <main>
323 <p>FreeIPA is a centralized idenity management solution developed
324 by Redhat. It is in my opinion the most functional libre alternative
325 to Microsoft's Active Directory. Like AD, FreeIPA integrates all of
326 the pieces needed to setup a domain including LDAP, Kerberos,
327 a Certificate Authority, and much more.</p>
328
329 <p>I will be using Fedora 35 in this tutorial. As of Debian 11, the
330 FreeIPA server is still not in the Debian repos. You will need either
331 a Fedora or a RHEL machine. A CentOS fork may work also but I have not
332 tested that.</p>
333
334 <h2>FreeIPA in an Enterprise</h2>
335
336 <p>For readers exploring the use of FreeIPA in a business
337 environment, note that FreeIPA documentation explicitly states that
338 it is not a replacement for Active Directory. I have not personally
339 tried to join a Windows computer to a FreeIPA domain, and so I can't
340 speak to how well that would work. FreeIPA would also not be able to push
341 out policy to Windows machines as is done with Group Policy. FreeIPA
342 is though able to create inter-domain trusts with an existing AD
343 infrastructure.</p>
344
345 <h2>The Case for FreeIPA at Home</h2>
346 <p>Using a full Kerberos and LDAP identity management server may
347 seem like overkill at home. And if you only have a single computer
348 then it probably is. But scaling up even slightly, to perhaps a small
349 family each with their own computer, will make having FreeIPA
350 advantageous (<em>your family is all using Linux, right?</em>). This
351 will be especially apparent if you are hosting your own services.
352 If you are for instance hosting a Jellyfin media server that everyone
353 in your family accesses, you won't want them to juggle separate
354 passwords for Jellyfin when you could just have them use the same
355 password they do on the computer. This single/same sign-on capability is
356 one of the most practically useful aspects of FreeIPA.</p>
357
358 <h2>Install Packages</h2>
359 <p>We start as usual by installing the required packages.</p>
360
361 <pre><code>dnf install freeipa-server freeipa-dns</code></pre>
362
363 <h2>Set Hostname</h2>
364 <p>The server will need to have a fully qualified hostname
365 before setting up IPA. You will need both a hostname for the server
366 itself and the domain name you will want for the FreeIPA domain. I
367 will be using <em>ipaserver.myhome.local</em>, where
368 <em>ipaserver</em> is the hostname and <em>myhome.local</em> is the
369 domain name.</p>
370
371 <pre><code>hostnamectl set-hostname <em>ipaserver.home.local</em></code></pre>
372
373 <p>We'll also need to add a hosts file entry to
374 <strong>/etc/hosts</strong>. Open that file in an editor and add a new
375 line with the IP of the server, the fully qualified name, and the
376 hostname.</p>
377
378 <pre><code>192.168.1.10 ipaserver.myhome.local ipaserver</code></pre>
379
380
381 <p>Make sure to reboot the server before continuing to complete
382 the hostname change.</p>
383
384 <h2>Firewall Configuration</h2>
385 <p>We'll need to allow several ports for FreeIPA to function properly.
386 Fedora 35 uses firewalld by default but I am going to disable that
387 in favor of UFW here.</p>
388
389 <pre><code><em>#Install UFW</em>
390dnf install ufw
391<em># Stop and disable firewalld</em>
392systemctl disable --now firewalld
393<em># Configure UFW</em>
394ufw enable
395ufw allow ssh
396ufw allow dns
397ufw allow 88 comment kerberos
398ufw allow 389 comment ldap
399ufw allow 443 comment webui
400ufw allow 636 comment ldaps
401ufw default deny incoming
402ufw reload</code></pre>
403
404 <h2>Configure FreeIPA</h2>
405 <p>Now we can run the FreeIPA setup script. This is an interactive but mostly
406 automatic process that will configure all of the IPA components. The
407 <strong>--mkhomedir</strong> flag will configure the server to create home
408 directories for IPA users on their first login and would otherwise have to be
409 done manually.</p>
410
411 <pre><code>ipa-server-install --mkhomedir</code></pre>
412
413 <p>That command will bring you into the install script. You will be prompted
414 several times before the bulk of the configuration happens. Default values
415 are show in brackets after the prompt. Let's run through those prompts.<br><br>
416 <strong>Do you want to configure integrated DNS (BIND)?</strong>:
417 <em>yes</em><br><br>
418 <strong>Sever host name</strong>: the default value should be showing
419 <em>ipaserver.myhome.local</em> which is what we want. Simply hit enter to acecpt
420 the default.<br><br>
421 <strong>Please confirm the domain name</strong>: The default here should be
422 correct <em>myhome.local</em> so hit enter to accept that.<br><br>
423 <strong>Please provide a realm name</strong>: This should just be the domain
424 name in all uppercase. If the default looks correct just hit enter.<br><br>
425 <strong>Directory Manager password</strong>: This is the password for an
426 administrator account used by system services. You will not need this for daily
427 use so I recommend setting it to a long randomly generated string. I have found
428 myself that using an extremely long password here will cause the installation to
429 fail. A password under 40 characters should be safe.<br><br>
430 <strong>IPA admin password</strong>: This is the password for your initial admin
431 user. Make this a strong password as this user has full admin rights for the
432 entire domain.<br><br>
433 <strong>Do you want to configure DNS forwarders</strong>: This allows you to
434 configure the IPA server to forward DNS requests to another DNS server for
435 zones it is not authoratitve for. The DNS server is configured by default as
436 a recursive DNS server so answering no does not prevent internet access. If you
437 have another DNS server that should be used instead then answer yes and provide
438 the IP address when prompted.<br><br>
439
440 <strong>Do you want to configure chrony with NTP server or pool address?</strong>
441 : Here you can configure a custom NTP server or pool for the NTP daemon chrony.
442 If you already have an NTP server on your network answer yes and provide its IP.
443 If you want to leave the deafult chrony configuration then answer no. Time
444 synchronization is very important in Kerberos so you should consider how you
445 want to achieve that on your network. If you do not have an NTP server you may
446 want to configure the IPA server as one later.<br><br>
447
448 <strong>Continue to configure the system with these values?</strong>: This is a
449 final confirmation before the script takes over and configures the IPA
450 components. Review the information printed and enter yes if it all looks correct.
451 </p>
452
453 <p>The install script will now run through configuration. This process usually
454 takes several minutes. When finished you should get a message saying
455 <strong>The ipa-server-install command was successful</strong>.</p>
456
457 <p>To finish, run this command to receive a Kerberos TGT. Provide the
458 password for the admin user when prompted.</p>
459
460 <pre><code>kinit admin</code></pre>
461
462 <h2>Accessing the Web Interface</h2>
463
464 <p>You are now able to manage FreeIPA through the web interface. You can
465 browse either to the IP or the hostname if your DNS is configured correctly.
466 You should see a screen similar to this.</p>
467
468 <img alt="FreeIPA Login Screen" src=../images/freeipa-webui.png>
469
470 <p>Login with the username admin and the password you set during the
471 insallation. You are now ready to begin configuring your IPA domain.</p>
472 </main>
473<p>
474<hr>
475Consider <a href=../donate.html>donating</a> if this article was useful.
476<a class=qr href=../images/bitcoin.png>[BTC]</a>
477</p>
478 </main>
479 <footer>
480 <a href=../kb.html>Knowledge Base</a>
481 <br>
482 <a href=../index.html>www.chudnick.com</a>
483 </footer>
484</body>
485</html>]]></description>
486 </item>
487 <item>
488 <title>Linux Software RAID</title>
489 <guid>https://www.chudnick.com/kb/mdadm-raid.html</guid>
490 <link>https://www.chudnick.com/kb/mdadm-raid.html</link>
491 <pubDate>Sun, 05 Jun 2022 15:19:11 -0400</pubDate>
492 <description><![CDATA[<!DOCTYPE html>
493<html lang=en>
494 <head>
495 <title></title>
496 <meta charset="utf-8"/>
497 <link rel="shortcut icon" href="favicon.ico"/>
498 <link rel='stylesheet' href='../style.css'/>
499 <meta name="viewport" content="width=device-width, initial-scale=1">
500 </head>
501<body>
502 <header><h1>Linux Software RAID</h1></header>
503 <main>
504 <p><strong>mdadm</strong> is a tool that allows for creation and
505 management of software RAID arrays on Linux. Creating an array
506 is a rather straightforward process.</p>
507
508 <h2>Install packages</h2>
509 <p>The only package needed is mdadm itself</p>
510 <pre><code>apt install mdadm</code></pre>
511
512 <h2>Partition disks</h2>
513 <p>We'll need to parition the disks to be used in the array before
514 creating it. This isn't anything complicated, we will just be
515 creating a single partition using all the space on each disk.</p>
516
517 <p>Use <strong>lsblk</strong> to get a list of disks attached to your system.</p>
518
519 <img src=../images/raid/lsblk.png alt="lsblk command">
520
521 <p>Then use <strong>fdisk</strong> to edit the partition table of the
522 first disk. In my case this would be <strong>/dev/sdb</strong>.
523 Be sure that you are selecting the correct disk as selecting the
524 wrong one can result in data being lost.</p>
525
526 <pre><code>fdisk /dev/sdb</code></pre>
527
528 <p>Use <strong>g</strong> to create a new GUID partition table.
529 Use <strong>n</strong> to create a new partition, and then just press
530 enter at all of the prompts to accept the defaults. Finally use
531 <strong>w</strong> to write the changes. You can use lsblk again
532 to verify the change and you should see that /dev/sdb now has a
533 partition <strong>/dev/sdb1</strong>.</p>
534
535 <img src=../images/raid/fdisk.png alt="fdisk command">
536
537 <p>Repeat this process for your other disks before continuing.</p>
538
539
540 <h2>Create the array</h2>
541 <p>Creating the array is done with a single command, but takes just a
542 bit of planning.</p>
543 <ul>
544 <li>Define an ID for the array, which is just a
545 number identifier. I use <em>0</em> in the command.</li>
546 <li>Determine the RAID level you want to use. I am going to
547 use RAID5 in this example. The argument to --level is the
548 number of the RAID level</li>
549 <li>Determine the devices that will be used in the array.
550 Somewhat contrary to the argument name, these devices
551 will actually be the partitions of the disks and not the
552 disks themselves. In the command, give the number of
553 partitions (<em>3</em>) and then a space-separated list of the
554 partitions that will be active in the array
555 (<em>/dev/sdb1 /dev/sdc1 /dev/sdd1</em>).</li>
556 <li>If you want to have any spare devices in the array you
557 will define them with the --spare-devices argument. These are
558 defined in the exact same way as the active RAID devices. In
559 the example I use <em>1</em> spare <em>/dev/sde1</em>. Spare
560 devices are hot-spares that will automatically be inserted into
561 the array if one of the disks fails.</li>
562 </ul>
563
564 <pre><code>mdadm --create /dev/md<em>0</em> --level=<em>5</em> --raid-devices=<em>3</em> <em>/dev/sdb1 /dev/sdc1 /dev/sdd1</em> --spare-devices=<em>1</em> <em>/dev/sde1</em></code></pre>
565
566 <p>After creating the array run the following command to get details
567 and the status of the array. It will take a bit to initialize the
568 array, you will know this is done when the state is clean. You do not
569 need to wait for the array to completely intialize to continue.</p>
570
571 <pre><code>mdadm --detail /dev/md<em>0</em></code></pre>
572
573 <p>Take note of the UUID and name values as we will need them in the
574 next step.</p>
575
576 <p>Before moving on we need to make a filesystem on the array. I'm
577 going to make a simple EXT4 filesystem here.</p>
578
579 <pre><code>mkfs.ext4 /dev/md<em>0</em></code></pre>
580
581
582 <h2>Configuration Files</h2>
583
584 <p>Open the mdadm configuration file at
585 <strong>/etc/mdadm/mdadm.conf</strong> and append this line. Replace
586 <em>uuid</em> and <em>name</em> with the values you got when running
587 mdadm --detail, replace <em>0</em> whatever ID you chose.</p>
588
589 <pre><code>ARRAY /dev/md<em>0</em> metadata=1.2 UUID=<em>uuid</em> name=<em>name</em></code></pre>
590
591 <p>Optionally, create an <strong>/etc/fstab</strong> entry for
592 automounting of the array. Replace /mnt/raid with the directory
593 where you want to mount the array. If you made a filesystem other than
594 ext4 make sure to change that value.</p>
595
596 <pre><code>/dev/md<em>0</em> /mnt/raid ext4 defaults 0 1</code></pre>
597
598<p>
599<hr>
600Consider <a href=../donate.html>donating</a> if this article was useful.
601<a class=qr href=../images/bitcoin.png>[BTC]</a>
602</p>
603 </main>
604 <footer>
605 <a href=../kb.html>Knowledge Base</a>
606 <br>
607 <a href=../index.html>www.chudnick.com</a>
608 </footer>
609</body>
610</html>
611
612 ]]></description>
613 </item>
614 <item>
615 <title>Integrating InfluxDB and Icinga</title>
616 <guid>https://www.chudnick.com/kb/icinga-influx.html</guid>
617 <link>https://www.chudnick.com/kb/icinga-influx.html</link>
618 <pubDate>Tue, 31 May 2022 06:22:43 -0400</pubDate>
619 <description><![CDATA[<<!DOCTYPE html>
620<html lang=en>
621 <head>
622 <title></title>
623 <meta charset="utf-8"/>
624 <link rel="shortcut icon" href="favicon.ico"/>
625 <link rel='stylesheet' href='../style.css'/>
626 <meta name="viewport" content="width=device-width, initial-scale=1">
627 </head>
628<body>
629 <header><h1>Integrating InfluxDB and Icinga</h1></header>
630 <main>
631 <p>Icinga2 has built-in support for writing monitoring data to InfluxDB.
632 This makes Icinga quite extensible as it allows for other programs to read
633 the gathered data from InfluxDB. For example, Icinga does not have built-in
634 graphing support. But monitoring data can be written to InfluxDB and then
635 consumed by a dedicated graphing tool like Grafana.</p>
636
637 <h2>Install Packages</h2>
638 <p>Let's install a few necessary packages</p>
639
640 <pre><code>apt install influxdb influxdb-client ssl-cert</code></pre>
641
642 <h2>Generate self-signed certificate</h2>
643 <p>Now generate a self-signed certificate for accessing InfluxDB over TLS</p>
644
645 <pre><code>make-ssl-cert generate-default-snakeoil
646usermod -aG ssl-cert influxdb</code></pre>
647
648 <h2>Create Database and Users</h2>
649 <p>Start and enable the InfluxDB service</p>
650
651 <pre><code>systemctl enable --now influxdb</code></pre>
652
653 <p>Now we'll create our database and users. We'll be creating 3 users with
654 different access rights. An admin user with full control over the database, a
655 user with write access that Icinga will use to write data to the database, and
656 a read-only user to allow external programs to read data from the database.</p>
657
658 <pre><code>influx -ssl -unsafeSsl -execute "create database icinga2; create user admin with password '<em>changeme</em>'; create user icingauser with password '<em>changeme</em>'; create user readonly with password '<em>changeme</em>'; grant all to admin; grant write on icinga2 to icingauser; grant read on icinga2 to readonly;"
659</code></pre>
660
661<h2>Configuration Files</h2>
662
663 <p>Then right InfluxDB's configuration file at
664 <em>/etc/influxdb/influxdb.conf</em></p>
665
666 <pre><code>reporting-enabled = false
667[meta]
668 dir = "/var/lib/influxdb/meta"
669[data]
670 dir = "/var/lib/influxdb/data"
671 wal-dir = "/var/lib/influxdb/wal"
672[coordinator]
673[retention]
674[shard-precreation]
675[monitor]
676[http]
677 enabled = true
678 bind-address = ":8086"
679 auth-enabled = true
680 https-enabled = true
681 https-certificate = "/etc/ssl/certs/ssl-cert-snakeoil.pem"
682 https-private-key = "/etc/ssl/private/ssl-cert-snakeoil.key"
683[ifql]
684[logging]
685[subscriber]
686[[graphite]]
687[[collectd]]
688[[opentsdb]]
689[[udp]]
690[continuous_queries]
691[tls]
692 min-version = "tls1.2"</code></pre>
693
694 <p>And restart InfluxDB to pickup the changes</p>
695
696 <pre><code>systemctl restart influxdb</code></pre>
697
698 <p>Then we need to configure Icinga to write data to our database. Start by
699 enabling the influxdb feature in Icinga</p>
700
701 <pre><code>icinga2 feature enable influxdb</code></pre>
702
703 <p>Now we tell Icinga how to write to our database. Open the configuration
704 file at <em>/etc/icinga2/features-available/influxdb.conf</em> and replace
705 with the following</p>
706
707 <pre><code>object InfluxdbWriter \"influxdb\" {
708 host = "127.0.0.1"
709 port = 8086
710 username = "icingauser"
711 password = "<em>icinga_password</em>"
712 ssl_enable = true
713 database = "icinga2"
714 flush_threshold = 1024
715 flush_interval = 10s
716 host_template = {
717 measurement = "$host.check_command$"
718 tags = {
719 hostname = "$host.name$"
720 }
721 }
722 service_template = {
723 measurement = "$service.check_command$"
724 tags = {
725 hostname = "$host.name$"
726 service = "$service.name$"
727 }
728 }
729}</code></pre>
730
731 <p>And finally restart Icinga to make those changes live.</p>
732
733 <pre><code>systemctl restart icinga2</code></pre>
734
735 <p>Icinga2 will now be writing the data it collects to your InfluxDB instance.</p>
736
737 </main>
738<p>
739<hr>
740Consider <a href=../donate.html>donating</a> if this article was useful.
741<a class=qr href=../images/bitcoin.png>[BTC]</a>
742</p>
743 </main>
744 <footer>
745 <a href=../kb.html>Knowledge Base</a>
746 <br>
747 <a href=../index.html>www.chudnick.com</a>
748 </footer>
749</body>
750</html>
751]]></description>
752 </item>
753 <item>
754 <title>Postfix and Dovecot Mail Server</title>
755 <guid>https://www.chudnick.com/kb/mail-server.html</guid>
756 <link>https://www.chudnick.com/kb/mail-server.html</link>
757 <pubDate>Mon, 30 May 2022 08:03:44 -0400</pubDate>
758 <description><![CDATA[<!DOCTYPE html>
759<html lang=en>
760<head>
761<title></title>
762<meta charset="utf-8"/>
763<link rel="shortcut icon" href="favicon.ico"/>
764<link rel='stylesheet' href='../style.css'/>
765<meta name="viewport" content="width=device-width, initial-scale=1">
766</head>
767<body>
768<header><h1>Postfix and Dovecot Mail Server</h1></header>
769<main>
770
771<p>Postfix and dovecot will be the two primary pieces of our mail sever.
772Postfix is the mail transport agent that handles the sending and
773receiving of mail and dovecot is the IMAP server that will allow us to
774access our mail from a mail client such as mutt. The server will also
775have several other supporting components, a complete list of which is:</p>
776
777<ul>
778 <li><em>SpamAssassin</em> for spam filtering</li>
779 <li><em>OpenDKIM</em> for DKIM verification and signing</li>
780 <li><em>Postgrey</em> for greylisting</li>
781 <li><em>Policyd-SPF</em> for SPF verification</li>
782 <li><em>OpenDMARC</em> for DMARC verification</li>
783</ul>
784
785<p>You can use <a href=https://git.chudnick.com/mail-tools/server/deploy-server>
786this script</a> I have written to automate this process, but I would
787recommend that you run through the tutorial first to understand
788what is being done.</p>
789
790<p>Please note that this tutorial is loosely intended for small personal mail
791servers. Using PAM for authentication, as is done here, is not a scalable solution
792for working with a large number of users. I do plan on covering Dovecot LDAP
793authentication at some point which would be a better solution in an enterprise
794setting.</p>
795
796<h2>Install Packages</h2>
797<p>Let's start by installing the required packages. Note that if you already
798have Apache installed on the server, replace <em>python3-certbot-nginx</em>
799with <em>python3-certbot-apache</em>.</p>
800<pre><code>apt install postfix dovecot-imapd dovecot-sieve opendkim opendkim-tools spamassassin gnupg postgrey postfix-policyd-spf-python opendmarc dbconfig-no-thanks certbot python3-certbot-nginx</code></pre>
801<p>During the installation of Postfix you will get a Debconf prompt in which
802you need to select "Internet Site" and then provide your domain name,
803<strong>example.com</strong>.</p>
804
805<h2>Get a certificate</h2>
806<p>Now we'll use Certbot to get a certificate for our server. If you are
807using Apache replace <em>nginx</em> with <em>apache2</em>.</p>
808
809<pre><code>systemctl stop nginx
810certbot certonly --standalone -d <strong>mail.example.com</strong>
811systemctl start nginx</code></pre>
812
813<h2>Postfix Main Configuration</h2>
814<p>In this section we will be doing the bulk of the postfix configuration.
815The postconf command used throughout appends (or changes)
816the specified configuration item in /etc/postfix/main.cf</p>
817
818<h3>Network Configuration</h3>
819
820<p>Let's start by configuring some network and domain information.</p>
821
822<pre><code>postconf -e "myorigin = <strong>example.com</strong>"
823postconf -e "mydestination = \$myhostname, \$mydomain, localhost"
824postconf -e "mynetworks = 127.0.0.0/8 [::1]/128"
825postconf -e "myhostname = <strong>mail.example.com</strong>"
826</code></pre>
827
828<p>Next, point postfix to the cerbot key and certificate, as well as the distro's
829CA certificates.</p>
830
831<pre><code>postconf -e "smtpd_tls_key_file=/etc/letsencrypt/live/<strong>mail.example.com</strong>/privkey.pem"
832postconf -e "smtpd_tls_cert_file=/etc/letsencrypt/live/<strong>mail.example.com</strong>/fullchain.pem"
833postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt"
834</code></pre>
835
836<p>Harden the TLS configuration by forcing strong
837protocols and ciphers, and requiring that authentication occur only over an
838encrypted session.</p>
839<pre><code><em># Require authentication over TLS and optionally use it for sending and receiving mail</em>
840postconf -e "smtpd_tls_auth_only = yes"
841postconf -e "smtpd_tls_security_level = may"
842postconf -e "smtp_tls_security_level = may"
843
844<em># Force the use of TLSv1.2 or TLSv1.3</em>
845postconf -e 'smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
846postconf -e 'smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
847postconf -e 'smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
848postconf -e 'smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
849
850<em># Prefer server ciphers</em>
851postconf -e "tls_preempt_cipherlist = yes"
852
853<em># Force strong ciphers</em>
854postconf -e "smtpd_tls_ciphers = high"
855postconf -e "smtpd_tls_mandatory_ciphers = high"
856postconf -e "smtp_tls_ciphers = high"
857postconf -e "smtp_tls_mandatory_ciphers = high"
858postconf -e "smtpd_tls_exclude_ciphers = aNULL, eNULL, EXP, LOW, MEDIUM, PSK, SRP, SHA1, kRSA, CAMELLIA, ARIA, DSS, RSA+AES, ADH, AECDH"
859postconf -e "smtp_tls_exclude_ciphers = aNULL, eNULL, EXP, LOW, MEDIUM, PSK, SRP, SHA1, kRSA, CAMELLIA, ARIA, DSS, RSA+AES, ADH, AECDH"
860</code></pre>
861
862<h3>Local Recipients and Aliases</h3>
863
864<p>Here we configure the bulk of the postfix built-in security settings which are
865structured as a series of access restrictions. Do not edit these settings without
866first reading the Postfix documentation as an incorrect change could inadvertently
867make your server an open relay.</p>
868
869<pre><code>postconf -e "smtpd_helo_required = yes"
870postconf -e "smtpd_sender_login_maps = proxy:hash:/etc/postfix/login_maps"
871postconf -e "smtpd_helo_restrictions = reject_unknown_helo_hostname, reject_non_fqdn_helo_hostname"
872postconf -e "smtpd_sender_restrictions = reject_sender_login_mismatch, reject_non_fqdn_sender, reject_unknown_sender_domain"
873postconf -e "smtpd_recipient_restrictions = reject_non_fqdn_recipient, reject_unknown_recipient_domain, permit_sasl_authenticated, reject_unauth_destination, check_policy_service unix:private/postgrey, check_policy_service unix:private/policyd-spf, reject_rbl_client zen.spamhaus.org"
874postconf -e "smtpd_relay_restrictions = permit_sasl_authenticated, reject_unauth_destination"
875postconf -e "smtpd_data_restrictions = reject_unauth_pipelining"
876
877<em># Disable VRFY command to prevent harvesting of user accounts on system</em>
878postconf -e "disable_vrfy_command = yes"
879
880<em># Change smptd banner (hide distribution)</em>
881postconf -e "smtpd_banner = \$myhostname ESMTP \$mail_name"</code></pre>
882
883<p>Now, configure the local mail recipients and some aliases. We'll create
884an account called <strong>mailadmin</strong> to receive mail addressed to
885several other accounts. This is to keep <em>administrative</em> mail separate, but
886you can certainly alias these to your main account later if you would prefer to see
887it there.</p>
888
889<pre><code><em># Set a custom local_recipient_maps here in order to avoid accepting mail for all local accounts</em>
890postconf -e "local_recipient_maps = proxy:hash:/etc/postfix/local_maps \$alias_maps"
891
892<em># You will need to manually set a password later to login as mailadmin</em>
893adduser --disabled-login --shell /usr/sbin/nologin --gecos "" mailadmin
894echo "# postfix aliases
895postmaster: mailadmin
896root: mailadmin
897dmarc: mailadmin
898" &gt; /etc/aliases
899
900<em># Update address databases</em>
901echo "mailadmin@<em>mail.example.com</em> mailadmin" &gt; /etc/postfix/login_maps
902echo "mailadmin mailadmin" &gt; /etc/postfix/local_maps
903newaliases
904postmap /etc/postfix/login_maps
905postmap /etc/postfix/local_maps
906</code></pre>
907
908<h3>Mail Delivery</h3>
909
910
911<p>These commands configure our mail delivery preferences. Mail will be
912delivered inside a user's home folder with a maildir-style mailbox using
913dovecot.</p>
914
915<pre><code><em># Maildir delivery to $HOME/Mail/Inbox/</em>
916postconf -e "home_mailbox = Mail/Inbox/"
917<em># Deliver mail with Dovecot</em>
918postconf -e "mailbox_command = /usr/lib/dovecot/deliver"</code></pre>
919
920<h3>Header and Body Checks</h3>
921
922<p>Header and body checks allow for some simple content filtering within Postfix.
923This is done by scanning a message line by line for a configured regex string,
924nothing more. For example, the first header check listed will reject a message
925with an attachment of <em>ransomware.exe</em> but will not block it if sent with
926no extension. This is mostly a protection against uneducated users and poorly
927written mail clients. Other checks block vulnerabilities and improve privacy.</p>
928
929<p>Create a new file <strong>/etc/postfix/header_checks</strong>, then open it in a
930text editor and add the following</p>
931<pre><code><em># Block files with common executable extensions</em>
932/name=[^&gt;]*\.(exe|pif|com|dll|vbs|bat|sh|bash|so|zip|tar|gz|cpio)/ REJECT
933
934<em># Block message/partial vulnerability</em>
935/message\/partial/ REJECT
936
937<em># Remove Received string that is created when spamassassin reinjects message into postfix</em>
938<em># This is to prevent leaking the userid of the spamassassin user</em>
939/^Received:.*userid.*/ IGNORE
940
941<em># Remove User-Agent strings from headers</em>
942/^User-Agent: .*/ IGNORE</code></pre>
943
944<p>Create another new file <strong>/etc/postfix/body_checks</strong>, and add this</p>
945<pre><code><em># Block messages with iframes</em>
946/&lt;iframe/ REJECT" &gt; /etc/postfix/body_checks</code></pre>
947
948<p>And then run these commands to point postfix to the check files.</p>
949<pre><code>postconf -e "header_checks = regexp:/etc/postfix/header_checks"
950postconf -e "body_checks = regexp:/etc/postfix/body_checks"</code></pre>
951
952<h2>Postfix Master Configuration</h2>
953<h3>SMTP client</h3>
954<p>This simple command configures the SMTP client process that is responsible
955for sending your mail to other mail servers.</p>
956
957<pre><code>postconf -M "smtp/unix=smtp unix - - y - - smtp"</code></pre>
958
959<h3>Postscreen and SMTP Recipient</h3>
960<p>Postscreen is a kind of firewall that sits in front of the Postfix SMTPD
961process and receives all incoming traffic. Postscreen will drop connections
962from IPs on a DNS blacklst, or from clients that violate the SMTP protocol by
963speaking out of turn or sending non-SMTP commands. This adds up to less spam
964connections and therefore a much lighter workload for your server.</p>
965
966<pre><code>postconf -M "smtp/inet=smtp inet n - y - 1 postscreen"
967postconf -M "smtpd/pass=smtpd pass - - y - - smtpd"
968postconf -P "smtpd/pass/content_filter=spamassassin"
969postconf -M "tlsproxy/unix=tlsproxy unix - - y - 0 tlsproxy"
970postconf -M "dnsblog/unix=dnsblog unix - - y - 0 dnsblog"
971postconf -e "postscreen_dnsbl_sites = zen.spamhaus.org"
972postconf -e "postscreen_dnsbl_action = enforce"
973postconf -e "postscreen_greet_action = enforce"
974</code></pre>
975
976<h3>Submission over TLS (submissions)</h3>
977<p>Submission over TLS (aka submissions) is the process you will use to submit
978mail to your server from a mail client. These commands configure submissions to
979use a fully-encrypted session, as opposed to STARTTLS, and to only allow access
980to authenticated clients.</p>
981
982<pre><code>postconf -M "submissions/inet=submissions inet n - y - - smtpd"
983postconf -P "submissions/inet/smtpd_tls_wrappermode=yes"
984postconf -P "submissions/inet/smtpd_tls_security_level=encrypt"
985postconf -P "submissions/inet/smtpd_tls_auth_only=yes"
986postconf -P "submissions/inet/smtpd_sasl_auth_enable=yes"
987postconf -P "submissions/inet/smtpd_client_restrictions=permit_sasl_authenticated,reject"
988postconf -P "submissions/inet/smtpd_helo_restrictions="
989postconf -P "submissions/inet/smtpd_sender_restrictions=reject_sender_login_mismatch"
990postconf -P "submissions/inet/smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject"
991postconf -P "submissions/inet/syslog_name=postfix/submissions"
992postconf -P 'submissions/inet/smtpd_tls_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'
993postconf -P 'submissions/inet/smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'</code></pre>
994
995<h3>OPTIONAL - submission with mandatory STARTTLS</h3>
996<p>Having configured submission over TLS on port 465 this step is optional.
997STARTTLS is considered by some to be less secure than full-session TLS and
998may be vulnerable to exploitation.</p>
999
1000<pre><code>postconf -M "submission/inet=submission inet n - y - - smtpd"
1001postconf -P "submission/inet/smtpd_tls_security_level=encrypt"
1002postconf -P 'submission/inet/smtpd_tls_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'
1003postconf -P 'submission/inet/smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'
1004postconf -P "submission/inet/smtpd_sasl_auth_enable=yes"
1005postconf -P "submission/inet/smtpd_tls_auth_only=yes"
1006postconf -P "submission/inet/syslog_name=postfix/submission"
1007postconf -P "submission/inet/smtpd_helo_restrictions="
1008postconf -P "submission/inet/smtpd_client_restrictions=permit_sasl_authenticated,reject"
1009postconf -P "submission/inet/smtpd_helo_restrictions="
1010postconf -P "submission/inet/smtpd_sender_restrictions=reject_sender_login_mismatch"
1011postconf -P "submission/inet/smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject"
1012</code></pre>
1013
1014<h3>SpamAssassin Configuration</h3>
1015<p>Finally, this command tells Postfix how to interact with SpamAssassin.</p>
1016
1017<pre><code>postconf -M "spamassassin/unix=spamassassin unix - n n - - pipe user=debian-spamd argv=/usr/bin/spamc --socket=/var/run/spamd.sock -e /usr/sbin/sendmail -oi -f \${sender} \${recipient}" </code></pre>
1018
1019<h2>Dovecot Configuration</h2>
1020<p>Dovecot configuration is usually split up into many different files under
1021<strong>/etc/dovecot/conf.d/</strong> but here will be doing all of the
1022configuration in the primary config file
1023<strong>/etc/dovecot/dovecot.conf</strong>. Open that file with your editor
1024of choice, clear all of its contents, and then replace it with the following.</p>
1025
1026<pre><code><em># /etc/dovecot/conf.d/10-auth.conf</em>
1027disable_plaintext_auth = yes
1028auth_username_format = %n
1029auth_mechanisms = plain
1030userdb {
1031 driver = passwd
1032}
1033passdb {
1034 driver = pam
1035}
1036
1037<em># /etc/dovecot/conf.d/10-mail.conf</em>
1038mail_location = maildir:~/Mail:INBOX=~/Mail/Inbox:LAYOUT=fs
1039namespace inbox {
1040 type = private
1041 prefix =
1042 separator = /
1043 inbox = yes
1044 subscriptions = yes
1045 list = yes
1046}
1047
1048<em># /etc/dovecot/conf.d/10-master.conf</em>
1049service imap-login {
1050# Run login processes in high-security mode (see: LoginProcess.txt in dovecot docs)
1051service_count = 1
1052# Disable unencrypted IMAP by setting port for plain IMAP to 0
1053 inet_listener imap {
1054 port = 0
1055 }
1056 inet_listener imaps {
1057 port = 993
1058 ssl = yes
1059 }
1060}
1061
1062<em># Allow postfix to use dovecot SASL</em>
1063service auth {
1064 unix_listener /var/spool/postfix/private/auth {
1065 mode = 0660
1066 user = postfix
1067 group = postfix
1068 }
1069}
1070
1071<em># /etc/dovecot/conf.d/10-ssl.conf</em>
1072ssl = required
1073ssl_key = &lt;/etc/letsencrypt/live/<strong>mail.example.com</strong>/privkey.pem
1074ssl_cert = &lt;/etc/letsencrypt/live/<strong>mail.example.com</strong>/fullchain.pem
1075ssl_client_ca_dir = /etc/ssl/certs
1076ssl_dh = &lt;/usr/share/dovecot/dh.pem
1077
1078<em># Mozilla intermediate compatibility</em>
1079ssl_min_protocol = TLSv1.2
1080ssl_cipher_list = ECDHE+ECDSA+AESGCM:ECDHE+aRSA+AESGCM:ECDHE+ECDSA+CHACHA20:ECDHE+aRSA+CHACHA20:DHE+aRSA+AESGCM:!aNULL:!eNULL
1081
1082ssl_prefer_server_ciphers = yes
1083ssl_client_require_valid_cert = yes
1084
1085
1086<em># /etc/dovecot/conf.d/15-lda.conf</em>
1087protocol lda {
1088 mail_plugins = \$mail_plugins sieve
1089}
1090
1091<em># /etc/dovecot/conf.d/15-mailboxes.conf</em>
1092namespace inbox {
1093 mailbox Sent {
1094 special_use = \Sent
1095 auto = subscribe
1096 }
1097 mailbox Trash {
1098 special_use = \Trash
1099 auto = create
1100 autoexpunge = 30d
1101 }
1102 mailbox Drafts {
1103 special_use = \Drafts
1104 auto = subscribe
1105 }
1106 mailbox Spam {
1107 special_use = \Junk
1108 auto = create
1109 autoexpunge = 30d
1110 }
1111 mailbox Archive {
1112 special_use = \Archive
1113 auto = create
1114 }
1115}
1116
1117<em># /etc/dovecot/conf.d/20-imap.conf</em>
1118imap_capability = +SPECIAL-USE
1119
1120<em># /etc/dovecot/conf.d/90-sieve.conf</em>
1121plugin {
1122 sieve = ~/.dovecot.sieve
1123 sieve_default = /var/lib/dovecot/sieve/default.sieve
1124 sieve_global = /var/lib/dovecot/sieve/
1125}</code></pre>
1126
1127<p>Then create the default sieve filtering script at
1128<strong>/var/lib/dovecot/sieve/default.sieve</strong></p>
1129<pre><code>require ["fileinto", "mailbox"];
1130/*
1131* Discard mail that has a spam score greater than or equal to 10
1132*/
1133if header :contains "X-Spam-Level" "**********" {
1134 discard;
1135 stop;
1136}
1137/*
1138* Discard messages marked as infected by a virus scanner
1139*/
1140if header :contains "X-Virus-Scan" "infected" {
1141 discard;
1142 stop;
1143}
1144/*
1145* If message is marked as spam (and falls below discard threshold) put into spam mailbox
1146*/
1147if header :contains "X-Spam-Flag" "YES" {
1148 fileinto "Spam";
1149}</code></pre>
1150
1151<p>And compile the script</p>
1152
1153<pre><code>sievec /var/lib/dovecot/sieve/default.sieve</code></pre>
1154
1155
1156<p>Finally, configure PAM authentication for dovecot at
1157<strong>/etc/pam.d/dovecot</strong>. Append these changes leaving any include
1158statements intact.</p>
1159<pre><code>auth required pam_unix.so
1160account required pam_unix.so</code></pre>
1161
1162<h2>OpenDKIM</h2>
1163<p>DKIM is a mail-verification method that cryptographically signs mail
1164to allow receivers to verify the authenticity of the sender. Our mail server
1165will use DKIM to validate signatures on incoming mail and sign outgoing mail. DKIM
1166requires a public key to be published via DNS, which will be done near the end of
1167the guide.</p>
1168
1169<p>Start by generating the DKIM key</p>
1170
1171<pre><code>opendkim-genkey -D /etc/dkimkeys -d <em>example.com</em> -s mail
1172chown opendkim: /etc/dkimkeys/*
1173chmod 600 /etc/dkimkeys/*
1174mv /etc/dkimkeys/mail.private /etc/dkimkeys/mail.pem</code></pre>
1175
1176<p>Here we make a directory for the opendkim socket inside the postfix chroot and
1177make it accessible to the postfix user.</p>
1178
1179<pre><code>mkdir /var/spool/postfix/opendkim
1180chmod 770 /var/spool/postfix/opendkim
1181chown opendkim:opendkim /var/spool/postfix/opendkim
1182usermod -aG opendkim postfix</code></pre>
1183
1184<p>Edit the configuration file at <strong>/etc/opendkim.conf</strong>
1185to be as follows:</p>
1186
1187<pre><code>On-BadSignature reject
1188On-Security reject
1189Syslog yes
1190SyslogSuccess yes
1191LogResults yes
1192Canonicalization simple
1193Mode sv
1194OversignHeaders From
1195Domain <strong>example.com</strong>
1196Selector mail
1197KeyFile /etc/dkimkeys/mail.pem
1198UserID opendkim
1199UMask 007
1200Socket local:/var/spool/postfix/opendkim/opendkim.sock
1201PidFile /run/opendkim/opendkim.pid
1202TemporaryDirectory /run/opendkim
1203InternalHosts 127.0.0.1
1204TrustAnchorFile /usr/share/dns/root.key
1205RequireSafeKeys True
1206AlwaysAddARHeader True
1207</code></pre>
1208
1209<h2>OpenDMARC</h2>
1210<p>DMARC is another mail-verification technology that provides verification of the
1211address seen by end-users and either or both of SPF and DKIM.
1212
1213<p>Like with OpenDKIM, we need to make a directory inside the postfix chroot
1214for the socket and assign proper permissions.</p>
1215<pre><code>mkdir /var/spool/postfix/opendmarc
1216chmod 770 /var/spool/postfix/opendmarc
1217chown opendmarc:opendmarc /var/spool/postfix/opendmarc
1218usermod -aG opendmarc postfix
1219</code></pre>
1220
1221<p>Now we write the configuration file at <strong>/etc/opendmarc.conf</strong></p>
1222
1223<pre><code>PidFile /run/opendmarc/opendmarc.pid
1224PublicSuffixList /usr/share/publicsuffix/public_suffix_list.dat
1225RejectFailures True
1226Socket local:/var/spool/postfix/opendmarc/opendmarc.sock
1227Syslog True
1228SyslogFacility mail
1229UMask 002
1230UserID opendmarc
1231HistoryFile /var/run/opendmarc/opendmarc.hist
1232SPFIgnoreResults True
1233SPFSelfValidate True
1234</code></pre>
1235
1236<p>Then create the history file and set permissions.</p>
1237
1238<pre><code>touch /var/run/opendmarc/opendmarc.hist
1239chown opendmarc:opendmarc /var/run/opendmarc/opendmarc.hist
1240chmod 664 /var/run/opendmarc/opendmarc.hist
1241</code></pre>
1242
1243<p>Now that both OpenDKIM and OpenDMARC are configured we can define them as milters
1244in postfix. This will tell postfix to route mail through one or both of these milters
1245depending on whether it is incoming or outgoing.</p>
1246
1247<pre><code>postconf -P "smtpd/pass/smtpd_milters=unix:opendkim/opendkim.sock,unix:opendmarc/opendmarc.sock"
1248postconf -P "submissions/inet/smtpd_milters=unix:opendkim/opendkim.sock"
1249<em># If you enabled submission on port 587 run this too</em>
1250postconf -P "submission/inet/smtpd_milters=unix:opendkim/opendkim.sock"
1251</code></pre>
1252
1253<h2>Postgrey</h2>
1254<p>Postgrey implements a spam-filter technique known as greylisting, which
1255always rejects mail on the first try and for a period of time afterwards known
1256as the greylist period. The idea behind this being that legitimate senders will
1257send the mail again later, while spammers, in a rush to send as many messages as
1258possible before being blacklisted, will not.</p>
1259
1260<p>Postgrey ships with an extensive whitelist domains that are known
1261to cause issues (mainly large providers that constantly send from different
1262addresses). This whitelist file is located at
1263<strong>/etc/postgrey/whitelist_clients</strong> and can be appended to include
1264any domain you do not wish to be subject to greylisting.</p>
1265
1266<p>The configuration needed here is minimal, just open
1267<strong>/etc/default/postgrey</strong> and make these changes</p>
1268
1269<pre><code>POSTGREY_OPTS="--unix=/var/spool/postfix/private/postgrey --privacy"
1270POSTGREY_TEXT="Greylisted - see https://www.greylisting.org"</code></pre>
1271
1272<p>And then enable the service</p>
1273
1274<pre><code>systemctl enable --now postgrey</code></pre>
1275
1276<h2>Policyd-SPF</h2>
1277<p>SPF is yet another mail-verification technology that uses DNS records to
1278delegate specific servers as being authorized to send mail for the domain
1279(and implicitly all other servers as unauthorized). Policyd-SPF will perform
1280SPF checking of received mail and reject mail that fails SPF verfication.</p>
1281
1282<p>First, tell postfix how to access Policyd-SPF</p>
1283
1284<pre><code>postconf -e "policyd-spf_time_limit = 3600"
1285postconf -M "policyd-spf/unix=policyd-spf unix - n n - 0 spawn user=policyd-spf argv=/usr/bin/policyd-spf"</code></pre>
1286
1287<p>And then edit the configuration file at
1288<strong>/etc/postfix-policyd-spf-python/policyd-spf.conf</strong></p>
1289
1290<pre><code>debugLevel = 1
1291TestOnly = 1
1292HELO_reject = Fail
1293Mail_From_reject = Fail
1294Header_Type = AR
1295<em># These settings increase false-positive risk</em>
1296<em># Comment them if you want to reduce that risk</em>
1297PermError_reject = True
1298TempError_Defer = True</code></pre>
1299
1300
1301<h2>SpamAssassin</h2>
1302<p>SpamAssassin is a spam-filter that will scan all received mail and assign
1303a spam score based on configured rules. SpamAssassin is much heavier and more
1304resource-intensive than any of the previous spam-filtering/verification programs
1305we have configured. The postfix spam-filtering philosophy emphasizes the use
1306of lightweight checks before passing to an external content filter such as
1307SpamAssassin. Ideally, non-legitimate mail will have already been caught by one
1308of the previous methods, and SpamAssassin will only have to operate on a much
1309smaller subset of the mail that is sent to our server.</p>
1310
1311<p>We have actually already told postfix to use SpamAssassin as a content filter
1312so in this section we just need to edit the configuration file
1313<strong>/etc/spamassassin/local.cf</strong>.</p>
1314
1315<pre><code><em># Clearly indicate message is spam to user</em>
1316rewrite_header Subject *****SPAM*****
1317rewrite_header From *****SPAM*****
1318
1319<em># Set required score to be marked as spam, 5.0 is default.</em>
1320<em># Lower to make policy more strict or raise to be more lenient.</em>
1321required_score 5.0
1322
1323<em># Attach original messages as text/plain instead of message/rfc822 to spam reports</em>
1324report_safe 2
1325
1326<em>Do not implicitly trust mail based on IP address except localhost</em>
1327trusted_networks 127.0.0.1/32
1328</code></pre>
1329
1330<p>And finally make a few changes to the defaults file at
1331<strong>/etc/default/spamassassin</strong></p>
1332
1333<pre><code>OPTIONS="--listen /var/run/spamd.sock --max-children 5"
1334PIDFILE=/var/run/spamd.pid
1335CRON=1</code></pre>
1336
1337<h2>Wrapping Up</h2>
1338<p>At this point we have done all of the necessary configuration of the mail
1339server programs. We have just a few more minor tasks before your mail server
1340is operational.</p>
1341
1342<h3>Configure Firewall</h3>
1343<p>We need to open the proper ports in the firewall. This example uses UFW.</p>
1344
1345<pre><code>ufw allow 25 comment "smtp"
1346ufw allow 465 comment "submission over TLS"
1347<em># Run this next command only if you enabled submission on port 587</em>
1348ufw allow 587 comment "mail submission"
1349ufw allow 993 comment "IMAP over TLS"
1350ufw reload</code></pre>
1351
1352<h3>Restart services</h3>
1353<p>Now let's restart the services to pick up any configuration changes.</p>
1354
1355<pre><code>systemctl restart postfix
1356systemctl restart dovecot
1357systemctl restart opendkim
1358systemctl restart opendmarc
1359systemctl enable --now spamassassin
1360systemctl restart spamassassin
1361systemctl restart postgrey</code></pre>
1362
1363<h3>DNS Entries</h3>
1364<p>Finally, we needs to set some required DNS records to enable mail flow and
1365verification. Begin by logging into your registrar or DNS host and editing
1366your DNS records.</p>
1367
1368<h3>A Record</h3>
1369<p>If you did not set a wildcard A record earlier, you will need to set one now
1370for <strong>mail</strong>.
1371Alternatively, if you are running the mail server on the same server as your
1372website, you may want to instead make a CNAME record pointing mail to www.</p>
1373
1374<h3>MX Record</h3>
1375<p>MX records tell servers attempting to send you mail where to send it. Open the
1376MX records section on your registrar and add a new record. An MX
1377record consists of a priority and a destination. Set the priority to 10 and the
1378destination to <strong>mail</strong>, or whatever your subdomain for this mail
1379server is. The host value can be left blank or may need to be set to "@"
1380depending on your registrar.</p>
1381
1382<h3>DKIM TXT Record</h3>
1383<p>Now we will set the three TXT records we need. Open the TXT records tab on
1384your registrar.</p>
1385
1386<p>We'll set the DKIM record first. The command we ran to
1387generate our DKIM keys also generates a DNS record for us which will be helpful
1388here. Print that to the screen with:</p>
1389
1390<pre><code>cat /etc/dkimkeys/mail.txt</code></pre>
1391
1392<p>You should get a lengthy output that looks something like the following. The
1393bolded portion is the value.</p>
1394
1395<pre><code>mail._domainkey IN TXT ( <strong>"v=DKIM1; h=sha256; k=rsa; "
1396 "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz50PSYL0Ob+OlF/0B77rwlzLe7zF6JKnxQNtMqcOCZ0Dar2FPhSUSz1FR0YmNuoShjMogdgKeojIzgRUqwK5GZ5Lz456qiXWkfAtLPc6UQ/WPoyEBGbJpRBYPGWdN4VoNcHkk/I4csvXW6MOI55ghPOwDmootPkCzNPR6gmNAXMe0duS4Lb+bIjy9QMOxGYVUaQ/b+7xar+fWw"
1397 "bA3DjQa3jTLCydzzJpjEMfVaKqNhQ4N+ve7O2Mb3LF5k5B977mtok/6POjVG5HY8g6Pba+GzMFItR6nJO5EE2fyfv6cNbRLsZiM+WQmqvDBst5ejaeapy86F5PdJFlX/TUgXjtuwIDAQAB"</strong> ) ; ----- DKIM key mail for example.com</code></pre>
1398
1399<p>You can cleanup the spacing of the value as your registrar should automatically
1400handle any needed splitting of the record. The parts you need to paste into your
1401registrar's web interface should then look like this.</p>
1402
1403<pre><code><em># Name/Host</em>
1404mail._domainkey
1405<em># TXT Value</em>
1406"v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz50PSYL0Ob+OlF/0B77rwlzLe7zF6JKnxQNtMqcOCZ0Dar2FPhSUSz1FR0YmNuoShjMogdgKeojIzgRUqwK5GZ5Lz456qiXWkfAtLPc6UQ/WPoyEBGbJpRBYPGWdN4VoNcHkk/I4csvXW6MOI55ghPOwDmootPkCzNPR6gmNAXMe0duS4Lb+bIjy9QMOxGYVUaQ/b+7xar+fWwbA3DjQa3jTLCydzzJpjEMfVaKqNhQ4N+ve7O2Mb3LF5k5B977mtok/6POjVG5HY8g6Pba+GzMFItR6nJO5EE2fyfv6cNbRLsZiM+WQmqvDBst5ejaeapy86F5PdJFlX/TUgXjtuwIDAQAB"</code></pre>
1407
1408<h3>DMARC TXT Record</h3>
1409<p>The DMARC record should be as follows:</p>
1410
1411<pre><code><em># Name/Host</em>
1412_dmarc
1413<em># Value</em>
1414"v=DMARC1; p=reject; rua=mailto:dmarc@<strong>example.com</strong>; fo=1"
1415</code></pre>
1416
1417<h3>SPF Record</h3>
1418<p>Your SPF record will look like this. Remember to replace
1419<strong>mail.example.com</strong> with your server name.</p>
1420
1421<pre><code><em># Name/Host</em>
1422@
1423<em># Value</em>
1424"v=spf1 a:<strong>mail.example.com</strong> -all"
1425</code></pre>
1426
1427<h3>PTR Record</h3>
1428<p>Many mail servers rely on PTR records for verification purposes so we need
1429to make sure our server's IP address resolves to the proper domain name. If
1430your mail server is residing on a VPS, you will need to add this record on your
1431VPS provider's interface, consult their documentation for details.</p>
1432
1433<h2>Creating your own Mail User</h2>
1434<p>Your mail server is now up and running. Let's create an email for you to
1435receive mail.</p>
1436
1437<pre><code>useradd --shell /usr/sbin/nologin --create-home --user-group <strong>user</strong>
1438echo "<strong>user@example.com user</strong>" &gt;&gt; /etc/postfix/login_maps
1439echo "<strong>user user</strong>" &gt;&gt; /etc/postfix/local_maps
1440postmap /etc/postfix/login_maps
1441postmap /etc/postfix/local_maps
1442postfix reload
1443</code></pre>
1444
1445<p>I have a script available for adding and removing users that you can find
1446<a href=https://git.chudnick.com/mail-tools/server/mailadm>here</a>.
1447
1448<h3>Connecting From a Mail Client</h3>
1449<p>When connecting your account to a mail client you need to use these settings.</p>
1450
1451<ul>
1452 <li>Username: <strong>user@example.com</strong> </li>
1453
1454 <li>Password: the password for <strong>user@example.com</strong> </li>
1455
1456 <li>Server name: <strong>mail.example.com</strong> </li>
1457
1458 <li>IMAP Port: 993</li>
1459
1460 <li>IMAP Connection: SSL/TLS</li>
1461
1462 <li>SMTP Port: 465</li>
1463
1464 <li>SMTP Connection Type: SSL/TLS</li>
1465
1466</ul>
1467<p>
1468<hr>
1469Consider <a href=../donate.html>donating</a> if this article was useful.
1470<a class=qr href=../images/bitcoin.png>[BTC]</a>
1471</p>
1472 </main>
1473 <footer>
1474 <a href=../kb.html>Knowledge Base</a>
1475 <br>
1476 <a href=../index.html>www.chudnick.com</a>
1477 </footer>
1478</body>
1479</html>]]></description>
1480</item>
1481<item>
1482 <title>Icinga2 Agent Configuration</title>
1483 <guid>https://www.chudnick.com/kb/icinga-agent.html</guid>
1484 <link>https://www.chudnick.com/kb/icinga-agent.html</link>
1485 <pubDate>Mon, 30 May 2022 08:03:44 -0400</pubDate>
1486 <description><![CDATA[<!DOCTYPE html>
1487<html lang=en>
1488 <head>
1489 <title></title>
1490 <meta charset="utf-8"/>
1491 <link rel="shortcut icon" href="favicon.ico"/>
1492 <link rel='stylesheet' href='../style.css'/>
1493 <meta name="viewport" content="width=device-width, initial-scale=1">
1494 </head>
1495<body>
1496 <header><h1>Icinga Agent Node Installation and Configuration</h1></header>
1497 <main>
1498 <p>With the Icinga master node configured, the servers we want
1499 to monitor can now be added as agent nodes. As the names suggest,
1500 the Icinga master node pushes the desired configuration to agent
1501 nodes, while agent nodes report the configured status checks back
1502 to the master. Communication between the master and agent nodes is
1503 encrypted via TLS, with the master node acting as a certificate
1504 authority.</p>
1505
1506 <p>You can find my script to automate this process
1507 <a href=https://git.chudnick.com/server-scripts/monitoring/icinga-agent>
1508 here</a>.</p>
1509
1510 <h2>Install Pakcages</h2>
1511 <p>Start by installing the required packages on the server to be
1512 monitored.</p>
1513
1514 <pre><code>apt install icinga2 monitoring-plugins
1515monitoring-plugins-contrib</code></pre>
1516
1517 <h2>Initialize PKI with master</h2>
1518 <p>Now we need to setup the PKI that will be used for the communication
1519 with the master node. The first step is to generate a certificate
1520 signing request. Replace <em>hostname</em> with the FQDN of the server.</p>
1521
1522 <pre><code>icinga2 pki new-cert --cn "<em>hostname</em>" --cert "/etc/icinga2/pki/<em>hostname</em>.crt" --csr "/etc/icinga2/pki/<em>hostname</em>.csr" --key "/etc/icinga2/pki/<em>hostname</em>.key"</code></pre>
1523
1524 <p>Next we save the master node's public key certificate. Replace
1525 <em>master</em> with the FQDN of your master node.</p>
1526
1527 <pre><code>icinga2 pki save-cert --host "<em>master</em>" --port 5665 --key "/etc/icinga2/pki/<em>hostname</em>.key" --trustedcert "/etc/icinga2/pki/trusted-master.crt"</code></pre>
1528
1529 <p>Receive signed certificate from the master node.</p>
1530
1531 <pre><code>icinga2 pki request --host "<em>master</em>" --port 5665 --key "/etc/icinga2/pki/<em>hostname</em>.key" --cert "/etc/icinga2/pki/<em>hostname</em>.crt" --trustedcert "/etc/icinga2/pki/trusted-master.crt" --ca "/etc/icinga2/pki/ca.crt"</code></pre>
1532
1533 <h2>Deploy configuration files</h2>
1534 <p>Write Icinga configuration.</p>
1535
1536 <pre><code><strong>/etc/icinga2/icinga2.conf</strong>
1537include "constants.conf"
1538const NodeName = "$nodename"
1539include "zones.conf"
1540include "features-enabled/*.conf"
1541include &lt;itl&gt;
1542include &lt;plugins&gt;
1543include &lt;plugins-contrib&gt;
1544include &lt;manubulon&gt;
1545include &lt;windows-plugins&gt;
1546include &lt;nscp&gt;"</code></pre>
1547
1548 <p>Write zones configuration.</p>
1549
1550 <pre><code><strong>/etc/icinga2/zones.conf</strong>
1551echo "object Endpoint "<em>hostname</em>" {}
1552object Zone "<em>hostname</em>" {
1553 parent = "<em>master</em>"
1554 endpoints = [ "<em>hostname</em>" ]
1555}
1556object Zone "<em>master</em>" {
1557 endpoints = [ "<em>master</em>" ]
1558}
1559object Endpoint "<em>master</em>" {
1560 host = "<em>master</em>"
1561}
1562object Zone "director-global" {
1563 global = true
1564}</code></pre>
1565
1566 <p>Write API configuration file.</p>
1567
1568 <pre><code><strong>/etc/icinga2/features-available/api.conf</strong>
1569echo "object ApiListener \"api\" {
1570 accept_commands = true
1571 accept_config = true
1572}</code></pre>
1573
1574 <h2>Enable API</h2>
1575 <p>Next, we need to enable the API on the agent.</p>
1576
1577 <pre><code>icinga2 feature enable api
1578
1579mkdir -p /var/lib/icinga2/certs
1580
1581cp /etc/icinga2/pki/<em>hostname</em>.crt /etc/icinga2/pki/<em>hostname</em>.key /etc/icinga2/pki/ca.crt /var/lib/icinga2/certs/
1582
1583chown -R nagios: /var/lib/icinga2/certs/</code></pre>
1584
1585 <h2>Sign agent CSR on Master</h2>
1586 <p>The only action needed on the master node is to sign the agent's
1587 CSR. Logon to your master node and run the following:</p>
1588
1589 <pre><code>fpr="$(icinga2 ca list | tail -1 | cut -d '|' -f 1)"
1590icinga2 ca sign $fpr</code></pre>
1591
1592 <h2>Configure Firewall</h2>
1593 <p>Before finishing we need to open the proper firewall port.
1594 I will use UFW in the example here and allow traffic only only
1595 from the master node for best security.</p>
1596
1597 <pre><code>ufw allow proto tcp from <em>master-ip</em> to any port 5665</code></pre>
1598
1599 <h2>Restart Icinga on Agent</h2>
1600 <p>Finally, restart the icinga service on the agent node.</p>
1601
1602 <pre><code>systemctl restart icinga2</code></pre>
1603
1604 <p>The Icinga agent node will now pull down configuration from the master.
1605 You will know that this worked if <em>/var/lib/icinga2/api/zones</em>
1606 begins to populate with new files.</p>
1607<p>
1608<hr>
1609Consider <a href=../donate.html>donating</a> if this article was useful.
1610<a class=qr href=../images/bitcoin.png>[BTC]</a>
1611</p>
1612 </main>
1613 <footer>
1614 <a href=../kb.html>Knowledge Base</a>
1615 <br>
1616 <a href=../index.html>www.chudnick.com</a>
1617 </footer>
1618</body>
1619</html>]]></description>
1620</item>
1621<item>
1622 <title>Icinga2 Director</title>
1623 <guid>https://www.chudnick.com/kb/icinga-director.html</guid>
1624 <link>https://www.chudnick.com/kb/icinga-director.html</link>
1625 <pubDate>Mon, 30 May 2022 08:03:44 -0400</pubDate>
1626 <description><![CDATA[<!DOCTYPE html>
1627<html lang=en>
1628 <head>
1629 <title></title>
1630 <meta charset="utf-8"/>
1631 <link rel="shortcut icon" href="favicon.ico"/>
1632 <link rel='stylesheet' href='../style.css'/>
1633 <meta name="viewport" content="width=device-width, initial-scale=1">
1634 </head>
1635<body>
1636 <header><h1>Icinga Director</h1></header>
1637 <main>
1638 <p>Icinga Director is the web-based configuration tool for Icinga2.
1639 Director provides a simple interface for configuring the various parts
1640 of your monitoring environment. Even if you would rather do all of
1641 the configuration from a terminal, I still recommend using Director for
1642 its self-service API which allows new nodes to register with no interaction
1643 required on the node (i.e. via a script).</p>
1644
1645 <p>Start by logging into your Icinga instance. If you followed the
1646 <a href=icinga2-master.html>master installation guide</a> you should have
1647 a tab labeled <strong>Icinga Director</strong>. Click on that, and you should
1648 see something similar to this:</p>
1649 <img src=../images/director/director.png>
1650
1651 <h2>Hosts</h2>
1652 <p>Let's start by looking at the hosts section. Clicking on the hosts
1653 button from the Director menu will present you with several options.
1654 Click on host templates, and then click add to define our first host
1655 template. Host templates are the building blocks of Icinga, they allow
1656 for your nodes to be structured however you see fit, and then to have
1657 monitoring checks automatically applied to them based on that structure.</p>
1658 <p>I like to structure my host templates by operating system. For example,
1659 I have a template called <strong>Linux Server</strong>, which is designed
1660 to encompass all of the Linux servers in my environment. I then get more
1661 specific, creating templates based on distro. These templates are children
1662 of the Linux Server template, so they inherit whatever is applied to the
1663 parent, but then can have distro-specific checks applied to themselves.</p>
1664 <p>Start by giving your template a name - I will use <strong>Linux Server
1665 </strong> here. Groups can be left empty for now, but you may want to
1666 add groups and apply them to templates later. The check command should
1667 be set to hostalive. Expand <strong>Icinga Agent and zone settings</strong>
1668 and set <em>Icinga2 Agent</em>, <em>Establish connection</em>,
1669 and <em>Accepts config</em> to Yes. Click store to save the template.
1670 Your template should look like this:</p>
1671
1672 <img src=../images/director/hosttemplate.png>
1673
1674 <h2>Service templates</h2>
1675 <p>Let's turn to services now. Return to the Director menu and select
1676 Services. The services menu is structured similar to hosts, and we will
1677 start with the service templates section. The idea behind service templates
1678 is very similar to host templates. Typically, a service template corresponds
1679 to a single monitoring command.</p>
1680 <p>As an example, we'll create a service template for a monitoring
1681 command that checks the status of a web server. Give the template a
1682 name, set the check command to http, and finally expand <strong>Icinga
1683 Agent and zone settings</strong> and set <strong>Run on agent
1684 </strong> to no. We set this to no because we want Icinga to query
1685 the web server externally instead of from the web server itself.</p>
1686
1687 <img src=../images/director/service-template.png>
1688
1689 <h2>Service sets</h2>
1690 <p>Service sets are simply groups of service templates. They can be
1691 structured however you see fit. Service sets can then be applied to
1692 hosts/host templates to have the checks be automatically applied.</p>
1693
1694 <p>Add a new service set and give it a name. Then click on the services
1695 tab and add all of the services you want to group into that set.
1696 Here is an example of a service set <strong>Linux Standard</strong>
1697 that has service checks that should be applied to all Linux servers.</p>
1698
1699 <img src=../images/director/service-set.png>
1700
1701 <p>To bring service sets and host templates together, return to your host
1702 templates, select Linux Server, select the services tab, and then select
1703 add service set and choose your desired set from the dropdown menu.</p>
1704
1705 <img src=../images/director/host-services.png>
1706
1707 <h2>Render your config</h2>
1708 <p>When you have made all of the changes you need you will need to
1709 render the Director configuration. Return to the Director menu,
1710 select Config Deployment, and then select Render config.</p>
1711
1712 <h2>Self Service API</h2>
1713 <p>In this last section we will look at what I think is the best feature
1714 of Director which is the self service API. To enroll a host template
1715 in the self service API, select the host template, select the agent
1716 tab, and select generate self service api key. That's it!
1717 The string of letters and numbers is the API key associated with this
1718 host template. Hosts can be enrolled with this API key and Icinga
1719 will automatically assign the host to this template. With proper
1720 structuring, you can have hosts be completely provisioned without
1721 touching Director. In the next article, we will use this to enroll
1722 a host in Icinga with a shell script.</p>
1723<p>
1724<hr>
1725Consider <a href=../donate.html>donating</a> if this article was useful.
1726<a class=qr href=../images/bitcoin.png>[BTC]</a>
1727</p>
1728 </main>
1729 <footer>
1730 <a href=../kb.html>Knowledge Base</a>
1731 <br>
1732 <a href=../index.html>www.chudnick.com</a>
1733 </footer>
1734
1735</body>
1736</html>]]></description>
1737</item>
1738<item>
1739 <title>Icinga2 Master Setup</title>
1740 <guid>https://www.chudnick.com/kb/icinga-master.html</guid>
1741 <link>https://www.chudnick.com/kb/icinga-master.html</link>
1742 <pubDate>Mon, 30 May 2022 08:03:44 -0400</pubDate>
1743 <description><![CDATA[<!DOCTYPE html>
1744<html lang=en>
1745 <head>
1746 <title></title>
1747 <meta charset="utf-8"/>
1748 <link rel="shortcut icon" href="favicon.ico"/>
1749 <link rel='stylesheet' href='../style.css'/>
1750 <meta name="viewport" content="width=device-width, initial-scale=1">
1751 </head>
1752<body>
1753<header><h1>Icinga2 Master Installation</h1></header>
1754<main>
1755<p>
1756This tutorial will cover the installation of the Icinga2
1757monitoring application master node. This includes the base
1758program, the web frontend, and the web-based configuration tool.
1759This guide was made for Debian but should be similar
1760on other distributions.
1761</p>
1762<p>
1763I have a script available to automate the steps described in this
1764tutorial available
1765<a href=https://git.chudnick.com/path/to/script>from my git repo</a>.
1766<h2>Install Packages</h2>
1767<p>Here we will install the required packages. Icinga can use either MySQL
1768or PostgreSQL, however this tutorial will use MySQL/MariaDB.</p>
1769<pre><code>apt install icinga2 icingaweb2 icinga2-ido-mysql icingaweb2-module-director monitoring-plugins monitoring-plugins-contrib default-mysql-server</code></pre>
1770<h2>Secure MySQL</h2>
1771<p>This step is optional but strongly recommended.
1772The mysql_secure_installation script will harden your MySQL instance.</p>
1773<pre><code>mysql_secure_installation</code></pre>
1774<p>I recommend the following responses:
1775<ul>
1776 <li><em>Switch to unix_socket authentication?</em><strong> Y</strong></li>
1777 <li><em>Change the root password?</em><strong> Y</strong></li>
1778 <li><em>Remove anonymous users?</em><strong> Y</strong></li>
1779 <li><em>Disallow root login remotely?</em><strong> Y</strong></li>
1780 <li><em>Remove the test database and access to it?</em><strong> Y</strong></li>
1781 <li><em>Reload privilege tables now?</em><strong> Y</strong></li>
1782</ul>
1783</p>
1784
1785<h2>Create Monitoring Database</h2>
1786<p>The next several sections will cover creating databases for the various
1787parts of Icinga. We'll start with the monitoring database.
1788The following command creates a MySQL database named <em>icinga2</em>
1789and grants permissions to a user named <em>ido_admin</em>. These values
1790are arbitrary, but I use them throughout the tutorial so I recommend leaving them
1791as is. You should definitely change the password though, which in the command
1792is <em>change me</em>. You will need this password and the passwords for the
1793other databases later, so make sure you save them.</p>
1794<pre><code>mysql -u root -e "CREATE DATABASE icinga2; GRANT SELECT, INSERT, UPDATE, DELETE, DROP, CREATE VIEW, INDEX, EXECUTE ON icinga2.* TO <em>ido_admin</em>@'localhost' IDENTIFIED BY '<em>change me</em>'; FLUSH PRIVILEGES;</code></pre>
1795
1796<p>We then need to import the ido schema into the database.</p>
1797
1798<pre><code>mysql -u root icinga2 &lt;/usr/share/icinga2-ido-mysql/schema/mysql.sql</code></pre>
1799
1800<p>After importing the schema, we then write the configuration file that tells
1801the monitoring module how to connect to the database.</p>
1802<pre><code><strong>/etc/icinga2/features-available/ido-mysql.conf</strong>
1803library "db_ido_mysql"
1804object IdoMysqlConnection "ido-mysql" {
1805 user = "ido_admin",
1806 password = "<em>ido_password</em>",
1807 host = "localhost",
1808 database = "icinga2"
1809}"</code></pre>
1810
1811<p>And finally we enable the monitoring module in Icinga.</p>
1812<pre><code>icinga2 feature enable ido-mysql</code></pre>
1813
1814<h2>Create Icingaweb2 Database</h2>
1815<p>This step is nearly identical to the last. This time we create a database
1816named <em>icingaweb2</em> and grant permissions to the user named
1817<em>icingaweb2_admin</em>.</p>
1818<pre><code>mysql -u root -e "CREATE DATABASE icingaweb2;GRANT ALL ON icingaweb2.* TO 'icingaweb2_admin'@'localhost' IDENTIFIED BY '<em>changeme</em>'; FLUSH PRIVILEGES;</code></pre>
1819
1820<p>Again we will need to import required schema into the database.</p>
1821<pre><code>mysql -u root icingaweb2 &lt;/usr/share/icingawbe2/etc/schema/mysql.schema.sql</code></pre>
1822
1823
1824<p>In this step we create the initial admin user that will be used to login
1825to the web interface. As is, this would create a user named <em>admin</em>
1826with the password <em>changme</em>. You should at least change the password.</p>
1827<pre><code>passhash="$(php -r "echo password_hash(\"<em>changeme</em>\", PASSWORD_DEFAULT);")"
1828mysql -u root -e "USE icingaweb2; INSERT INTO icingaweb_user (name, active, password_hash) VALUES (\"<em>admin</em>\", 1, \"$passhash\"); FLUSH PRIVILEGES;"</code></pre>
1829
1830<h2>Create Icinga Director Database</h2>
1831<p>Here we create the database for Director. Director will require more
1832configuration later, so for now we will just be creating the database.</p>
1833<pre><code>mysql -u root -e "CREATE DATABASE director CHARACTER SET 'utf8'; GRANT ALL on director.* TO 'director'@'localhost' IDENTIFIED BY '$director_password';FLUSH PRIVILEGES;"</code></pre>
1834
1835<h2>Setup Icinga2 API</h2>
1836<p>Run the following command to initialize the Icinga API.</p>
1837<pre><code>icinga2 api setup</code></pre>
1838<p>And then restart Icinga to apply the changes.</p>
1839<pre><code>systemctl restart icinga2</code></pre>
1840
1841<h2>Configure Web Server</h2>
1842<p>In this section we will configure the web server for accessing
1843Icinga's web interface and Director configuration tool.
1844This tutorial will use nginx but apache could be used as well.
1845We'll start by installing the necessary packages.</p>
1846<pre><code>apt install nginx php-fpm</code></pre>
1847<p>Then we need to create the site configuration file.<p>
1848<pre><code><strong>/etc/nginx/sites-available/icingaweb2.conf</strong>
1849server {
1850 listen 80;
1851 server_name <em>monitoring.example.com</em>
1852 location ~ ^/icingaweb2/index\.php(.*)$ {
1853 fastcgi_pass unix:/var/run/php/php-fpm.sock;
1854 fastcgi_index index.php;
1855 include fastcgi_params;
1856 fastcgi_param SCRIPT_FILENAME /usr/share/icingaweb2/public/index.php;
1857 fastcgi_param ICINGAWEB_CONFIGDIR /etc/icingaweb2;
1858 fastcgi_param REMOTE_USER $remote_user;
1859 }
1860
1861 location ~ ^/icingaweb2(.+)? {
1862 alias /usr/share/icingaweb2/public;
1863 index index.php;
1864 try_files $1 $uri $uri/ /icingaweb2/index.php$is_args$args;
1865 }
1866
1867 <em># Not strictly necessary but allows you to get to icinga without
1868 # specifying /icingaweb2 in the URL.</em>
1869 location = / {
1870 return 302 http://$host/icingaweb2;
1871 }
1872
1873}</code></pre>
1874<p>And then restart nginx to pick up the changes.</p>
1875<pre><code>systemctl restart nginx</code></pre>
1876
1877<p>At this point we are done with the Icinga setup module and so we
1878can disable it.</p>
1879<pre><code>icingacli module disable setup</code></pre>
1880
1881<h2>Write Configuration Files</h2>
1882<p>In this section we will write several configuration files. Icinga uses
1883the INI format for its web interface configuration files.</p>
1884<p>In this first file we tell Icinga about the various resources it should have
1885access to. These resources are the three databases created previously.
1886Replace the password in each section with the corresponding password you set
1887for that database earlier.</p>
1888<pre><code><strong>/etc/icingaweb2/resources.ini</strong>
1889[icinga2]
1890type = "db"
1891db = "mysql"
1892host = "localhost"
1893port = ""
1894dbname = "icinga2"
1895username = "ido_admin"
1896password = "<em>ido password</em>"
1897charset = ""
1898use_ssl = "0"
1899
1900[icingaweb2]
1901type = "db"
1902db = "mysql"
1903host = "localhost"
1904port = ""
1905dbname = "icingaweb2"
1906username = "icingaweb2_admin"
1907password = "<em>ido password</em>"
1908charset = ""
1909use_ssl = "0"
1910
1911
1912[director]
1913type = "db"
1914db = "mysql"
1915host = "localhost"
1916port = ""
1917dbname = "director"
1918username = "director"
1919password = "<em>director password</em>"
1920charset = "utf8"
1921use_ssl = "0"
1922</code></pre>
1923
1924<p>This file controls the authentication settings for the web interface.
1925Here we tell Icinga to look at the icingaweb2 database for
1926authentication purposes.</p>
1927<pre><code><strong>/etc/icingaweb2/authentication.ini</strong>
1928[icingaweb2]
1929backend = "db"
1930resource = "icingaweb2"</code></pre>
1931
1932<p>Now we tell icinga which users should have admin permissions.
1933If you changed the username value from <em>admin</em> previously, be sure to update
1934it here.</p>
1935<pre><code><strong>/etc/icingaweb2/roles.ini</strong>
1936[admins]
1937users = "<em>admin</em>"
1938resource = "icingaweb2"</code></pre>
1939
1940<p>Enable the web interface monitoring module.</p>
1941<pre><code>icingacli module enable monitoring</code></pre>
1942<p>Then write the configuration file pointing the monitoring module to the
1943monitoring database.</p>
1944<pre><code><strong>/etc/icingaweb2/modules/monitoring/backends.ini</strong>
1945[icinga]
1946type = "ido"
1947resource = "icinga2"</code></pre>
1948
1949<p>Here we configure Icinga to use the API for communication.
1950You will need to get your unique API password generated during the API setup from
1951from <strong>/etc/icinga2/conf.d/api-users.conf</strong>.
1952<em>hostname</em> should be the FQDN of the server.</p>
1953<pre><code><strong>/etc/icingaweb2/modules/monitoring/commandtransports.ini</strong>
1954[icinga2]
1955transport = "api"
1956host = <em>hostname</em>
1957port = "5665"
1958username = "root"
1959password = "<em>api password</em>"</code></pre>
1960
1961<p>Lastly, tell Icinga to protect variables with potentially sensitive values.</p>
1962<pre><code><strong>/etc/icingaweb2/modules/monitoring/config.ini</strong>
1963[security]
1964protected_customvars = "*pw*,*pass*,*community*"</code></pre>
1965
1966
1967<h2>Configure Director</h2>
1968<p>This section will cover configuring Director configuration tool.</p>
1969<p>Create Director module configuration directory.</p>
1970<pre><code>mkdir -p /etc/icingaweb2/modules/director</code></pre>
1971
1972<p>Write the Director configuration file.</p>
1973<pre><code><strong>/etc/icingaweb2/modules/director/config.ini</strong>
1974[db]
1975resource = "director"</code></pre>
1976
1977<p>Enable Director module and run the initial migration.</p>
1978<pre><code>icingacli module enable director
1979icingacli director migration run</code></pre>
1980
1981<p>Write Director kickstart configuration file.</p>
1982<pre><code><strong>/etc/icingaweb2/modules/director/kickstart.ini</strong>
1983[config]
1984endpoint = "<em>hostname</em>"
1985username = "root"
1986password = "<em>api password</em>"</code></pre>
1987
1988<p>Kickstart Director, then render and deploy the configuration.</p>
1989<pre><code>icingacli director kickstart run
1990icingacli director config render
1991icingacli director config deploy</code></pre>
1992
1993<p>Director is setup at this point so we will shred the unneeded configuration
1994file containing sensitive information.</p>
1995<pre><code>shred -uz /etc/icingaweb2/modules/director/kickstart.ini</code></pre>
1996
1997<h2>Login to your Monitoring Instance</h2>
1998<p>You are now ready to login to your monitoring instance with the admin
1999user created previously. Open a web browser and go to
2000http://<em>hostname</em>/icingaweb2. You should see a screen similar to this:</p>
2001<a href=../images/icinga-login.png><img src=../images/icinga-login.png alt="Icinagweb2 Login Screen"></a>
2002
2003<h2>Next Steps</h2>
2004<p>In the following articles we will go through setting up Icinga2 agents on servers, and configure your monitoring instance through Icinga Director.</p>
2005<p>
2006<hr>
2007Consider <a href=../donate.html>donating</a> if this article was useful.
2008<a class=qr href=../images/bitcoin.png>[BTC]</a>
2009</p>
2010 </main>
2011 <footer>
2012 <a href=../kb.html>Knowledge Base</a>
2013 <br>
2014 <a href=../index.html>www.chudnick.com</a>
2015 </footer>
2016</body>
2017</html>]]></description>
2018</item>
2019 </channel>
2020</rss>
diff --git a/software.html b/software.html
new file mode 100644
index 0000000..928ccfc
--- /dev/null
+++ b/software.html
@@ -0,0 +1,57 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' type='text/css' href='style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1 class=pagetop>Software I Use</h1></header>
12 <main>
13 <p>This is some of the software that I use and recommend.
14 It goes without saying, but all of this software is free as in freedom,
15 libre, open source.</p>
16
17 <h2>Desktop Programs</h2>
18 <p><strong>Window Manager</strong> - dwm
19 <a class=qr href="https://git.chudnick.com/dwm">[git]</a></p>
20 <p><strong>Shell</strong> - zsh</p>
21 <p><strong>Terminal Emulator</strong> - urxvt</p>
22 <p><strong>Statusbar</strong> - dwmblocks
23 <a class=qr href="https://git.chudnick.com/dwmblocks">[git]</a></p>
24 <p><strong>Text Editor</strong> - vim</p>
25 <p><strong>Music Player</strong> - cmus</p>
26 <p><strong>Process Monitor</strong> - htop</p>
27 <p><strong>Media Player</strong> - mpv</p>
28 <p><strong>Email</strong> - neomutt, isync, msmtp
29 <a class=qr href=articles/mutt.html>[kb]</a></p>
30 <p><strong>RSS</strong> - newsboat</p>
31 <p><strong>PDF Reader</strong> - zathura</p>
32 <p><strong>Sandbox</strong> - firejail</p>
33 <p><strong>Virtualization</strong> - qemu/kvm + libvirt</p>
34 <p><strong>Firewall</strong> - ufw</p>
35
36 <h2>Server Software</h2>
37 <p>This is some server oriented software that I use.</p>
38 <p><strong>Mail Server</strong> - postfix + dovecot
39 <a class=qr href=articles/mail-server.html>[kb]</a></p>
40
41 <p><strong>Media Server</strong> - jellyfin</p>
42
43 <p><strong>Server Monitoring</strong> - icinga2
44 <a class=qr href=articles/icinga-master.html>[kb]</a></p>
45
46 <p><strong>Configuration Management</strong> - ansible</p>
47
48 <p><strong>Identity Management</strong> - FreeIPA
49 <a class=qr href=articles/freeipa-server.html>[kb]</a></p>
50
51
52
53 </main>
54 <footer><a href=index.html>www.chudnick.com</a></footer>
55</body>
56</html>
57
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..db70bd3
--- /dev/null
+++ b/style.css
@@ -0,0 +1,173 @@
1body {
2 color: snow;
3 background: rgb(10,10,10);
4 font-size: 14pt;
5}
6
7h1 {
8 text-align: center;
9}
10
11h1.pagetop {
12 border-bottom: 2px solid;
13}
14
15div.quicklinks {
16 text-align: left;
17}
18
19a {
20 color: skyblue;
21 font-size: 14pt;
22}
23
24a.qr {
25 color: skyblue;
26 font-size: 12pt;
27}
28
29a:hover {
30 color: firebrick;
31}
32
33img {
34 margin: auto ;
35 max-width: 60%;
36 display: block;
37 border: solid 1px;
38 color: snow;
39}
40
41img.ql {
42 margin: auto ;
43 max-width: 60%;
44 display: block;
45 border: none;
46 color: snow;
47}
48
49footer {
50 text-align: center;
51}
52
53ul {
54 text-align: left;
55 font-size: 13pt;
56 max-width: 800px;
57 margin: 1em auto ;
58}
59
60p {
61 text-align: left;
62 font-size: 14pt;
63 max-width: 800px;
64 margin: 1em auto ;
65}
66
67p.donate {
68 text-align: center;
69}
70
71h2 {
72 color: firebrick;
73 text-align: left;
74 font-size: 20pt;
75 border-bottom: solid 1px;
76 max-width: 800px;
77 margin: 1em auto ;
78 padding-top: 20px;
79 padding-bottom: 5px;
80}
81
82h2.donate {
83 text-align: center;
84 border-bottom: none;
85}
86
87h3 {
88 color: firebrick;
89 text-align: left;
90 font-size: 16pt;
91 max-width: 800px;
92 margin: 1em auto ;
93 padding-top: 20px;
94 padding-bottom: 5px;
95}
96
97em {
98 color: orange;
99}
100
101strong {
102 color: deepskyblue;
103}
104
105/* Sidebar */
106
107div.sidebar, div.kbtoc {
108 text-align: left;
109 border-top: 2px solid;
110 border-right: 2px solid;
111 padding-right: 10px;
112 max-width: 33%;
113 height: 100%;
114 position: fixed;
115 overflow: auto;
116}
117
118li.sidebar,li.toc-l1 {
119 text-align: left;
120 list-style: none;
121 padding: 15px 0 0 0;
122 font-size: 14pt;
123}
124
125a.sidebar, a.toc-l1 {
126 text-decoration: none;
127}
128
129li.toc-l2 {
130 text-align: left;
131 list-style: none;
132 padding: 25px 0 0 0;
133 font-size: 14pt;
134}
135
136img.ql {
137 margin: auto ;
138 max-width: 60%;
139 display: inline;
140 border-radius: 10px;
141}
142
143/* My Setup */
144
145div.desktop-image {
146 text-align: center;
147}
148
149p.sw-desc {
150 margin-left: 5%;
151}
152
153/* Knowlede Base */
154
155h2.kb {
156 text-align: center;
157}
158
159code {
160 color: snow ;
161 border-radius: 5px ;
162 font-size: 11pt;
163}
164
165pre {
166 background: darkslategray ;
167 border: 2px darkgray solid ;
168 padding: 1em ;
169 white-space: pre-wrap;
170 overflow-wrap: break-word ;
171 max-width: 600px ;
172 margin: auto ;
173}
diff --git a/template.html b/template.html
new file mode 100644
index 0000000..f21a528
--- /dev/null
+++ b/template.html
@@ -0,0 +1,18 @@
1<!DOCTYPE html>
2<html lang=en>
3 <head>
4 <title></title>
5 <meta charset="utf-8"/>
6 <link rel="shortcut icon" href="favicon.ico"/>
7 <link rel='stylesheet' type='text/css' href='style.css'/>
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 </head>
10<body>
11 <header><h1 class=pagetop>Placeholder</h1></header>
12 <main>
13 This is a placeholder page.
14 </main>
15 <footer><a href=index.html>www.chudnick.com</a></footer>
16</body>
17</html>
18