<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Seun B's blog]]></title><description><![CDATA[Seun B's blog]]></description><link>https://devblog.seunb.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 16:03:13 GMT</lastBuildDate><atom:link href="https://devblog.seunb.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A Simple Foundation for Data Security: Public-Key Encryption with OpenSSL]]></title><description><![CDATA[In today’s world, keeping data safe is more important than ever. Public-key encryption is one of the basic building blocks for data security. It lets two people share secret messages over an open network without ever sharing a password. We’ll work in...]]></description><link>https://devblog.seunb.com/a-simple-foundation-for-data-security-public-key-encryption-with-openssl</link><guid isPermaLink="true">https://devblog.seunb.com/a-simple-foundation-for-data-security-public-key-encryption-with-openssl</guid><category><![CDATA[#cybersecurity]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Data security]]></category><category><![CDATA[openssl]]></category><dc:creator><![CDATA[Seun B]]></dc:creator><pubDate>Wed, 02 Jul 2025 00:31:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751416064957/c6df1151-ef72-490e-8d84-65f7dff6ea70.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today’s world, keeping data safe is more important than ever. Public-key encryption is one of the basic building blocks for data security. It lets two people share secret messages over an open network without ever sharing a password. We’ll work in a Linux environment and use the <code>openssl</code> command-line tool, which is installed by default on most distributions.</p>
<p>To keep things clear, we create two separate folders with restricted permissions:</p>
<ul>
<li><strong>Professor’s folder</strong> (<code>~/Desktop/Prof</code>): only the professor can read or write here.</li>
<li><strong>Student’s folder</strong> (<code>~/Desktop/Student</code>): only the student can read or write here.</li>
</ul>
<p>This setup mimics real-world security: each user protects their private keys in their own secure directory.</p>
<hr />
<h3 id="heading-1-create-and-protect-workspaces">1. Create and Protect Workspaces</h3>
<pre><code class="lang-bash">mkdir ~/Desktop/Prof
chmod 700 ~/Desktop/Prof

mkdir ~/Desktop/Student
chmod 700 ~/Desktop/Student
</code></pre>
<hr />
<h3 id="heading-2-professor-generates-an-rsa-key-pair">2. Professor Generates an RSA Key Pair</h3>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~/Desktop/Prof

<span class="hljs-comment"># Generate a 2048-bit private key</span>
openssl genrsa -out PrivateKeyA.pem 2048

<span class="hljs-comment"># Derive the public key from that private key</span>
openssl rsa -<span class="hljs-keyword">in</span> PrivateKeyA.pem -pubout -out PublicKeyA.pem

<span class="hljs-comment"># Verify the files exist</span>
ls -l
</code></pre>
<p><strong>Example output</strong>:</p>
<pre><code class="lang-text">total 12
-rw------- 1 you you 1679 Jun 30 09:00 PrivateKeyA.pem
-rw-r--r-- 1 you you  450 Jun 30 09:00 PublicKeyA.pem
</code></pre>
<ul>
<li><code>PrivateKeyA.pem</code> is the secret key (owner-only permissions).</li>
<li><code>PublicKeyA.pem</code> is the public key (readable by others).</li>
</ul>
<hr />
<h3 id="heading-3-student-generates-their-rsa-key-pair">3. Student Generates Their RSA Key Pair</h3>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~/Desktop/Student

openssl genrsa -out PrivateKeyB.pem 2048
openssl rsa -<span class="hljs-keyword">in</span> PrivateKeyB.pem -pubout -out PublicKeyB.pem

ls -l
</code></pre>
<p><strong>Example output</strong>:</p>
<pre><code class="lang-text">total 12
-rw------- 1 you you 1679 Jun 30 09:05 PrivateKeyB.pem
-rw-r--r-- 1 you you  450 Jun 30 09:05 PublicKeyB.pem
</code></pre>
<hr />
<h3 id="heading-4-professor-encrypts-a-message-for-the-student">4. Professor Encrypts a Message for the Student</h3>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~/Desktop/Prof

<span class="hljs-comment"># Create a plaintext file</span>
cat &gt; secret.txt
This is a secret message.
^D

<span class="hljs-comment"># Encrypt it with the student’s public key</span>
openssl rsautl -encrypt \
  -<span class="hljs-keyword">in</span> secret.txt \
  -out secret.enc \
  -inkey ~/Desktop/Student/PublicKeyB.pem \
  -pubin

ls -l
</code></pre>
<p><strong>Example output</strong>:</p>
<pre><code class="lang-text">total 16
-rw-r--r-- 1 you you   28 Jun 30 09:10 secret.txt
-rw------- 1 you you 1679 Jun 30 09:00 PrivateKeyA.pem
-rw-r--r-- 1 you you  450 Jun 30 09:00 PublicKeyA.pem
-rw-r--r-- 1 you you  256 Jun 30 09:10 secret.enc
</code></pre>
<p>To peek at the encrypted file:</p>
<pre><code class="lang-bash">cat secret.enc
</code></pre>
<p><strong>Example output</strong> (binary gibberish):</p>
<pre><code class="lang-text">�����V�j���x�u...�^�
</code></pre>
<hr />
<h3 id="heading-5-student-decrypts-the-message">5. Student Decrypts the Message</h3>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~/Desktop/Student

<span class="hljs-comment"># Copy secret.enc from Prof folder (or share it)</span>
<span class="hljs-comment"># Then decrypt with the student’s private key</span>
openssl rsautl -decrypt \
  -<span class="hljs-keyword">in</span> ~/Desktop/Prof/secret.enc \
  -out secret.dec \
  -inkey PrivateKeyB.pem

ls -l
</code></pre>
<p><strong>Example output</strong>:</p>
<pre><code class="lang-text">total 20
-rw-r--r-- 1 you you   28 Jun 30 09:05 secret.txt      # if student made one
-rw-r--r-- 1 you you  256 Jun 30 09:10 secret.enc
-rw-r--r-- 1 you you   28 Jun 30 09:10 secret.dec
-rw------- 1 you you 1679 Jun 30 09:05 PrivateKeyB.pem
-rw-r--r-- 1 you you  450 Jun 30 09:05 PublicKeyB.pem
</code></pre>
<p>To view the recovered message:</p>
<pre><code class="lang-bash">cat secret.dec
</code></pre>
<p><strong>Example output</strong>:</p>
<pre><code class="lang-text">This is a secret message.
</code></pre>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>This simple workflow shows the foundation of public-key encryption in data security:</p>
<ol>
<li><strong>Generate</strong> a private/public key pair (<code>openssl genrsa</code> + <code>openssl rsa -pubout</code>).</li>
<li><strong>Encrypt</strong> with the recipient’s public key (<code>openssl rsautl -encrypt</code>).</li>
<li><strong>Decrypt</strong> with the matching private key (<code>openssl rsautl -decrypt</code>).</li>
</ol>
<p>Because each private key never leaves its owner’s protected folder, this method secures data even over untrusted networks. Public-key encryption like this is the basic building block for many secure systems, HTTPS websites, secure email, VPNs, and more.</p>
<p>At its core, this example illustrates <strong>asymmetric cryptography</strong> in its purest form, anyone can encrypt a message using a public key, yet only the holder of the corresponding private key can unlock it. 
Real-world systems add certificates, use faster symmetric ciphers for large data, and automate key management, but they all still rely on these same three steps.</p>
<p>Try it yourself in a Linux lab, generate your own keys, lock and unlock a file, and you’ll see how public-key cryptography keeps information safe from prying eyes.</p>
]]></content:encoded></item><item><title><![CDATA[Artifactory: Centralizing Artifact Management for DevOps Success]]></title><description><![CDATA[Introduction
In software development environment, the need for efficient artifact management is paramount. As a DevOps Engineer, I recognized the necessity of streamlining the deployment process and ensuring a reliable artifact repository for Java ap...]]></description><link>https://devblog.seunb.com/artifactory-centralizing-artifact-management-for-devops-success</link><guid isPermaLink="true">https://devblog.seunb.com/artifactory-centralizing-artifact-management-for-devops-success</guid><category><![CDATA[Linux]]></category><category><![CDATA[Artifacts]]></category><category><![CDATA[Devops]]></category><category><![CDATA[software development]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[Tomcat]]></category><category><![CDATA[maven]]></category><category><![CDATA[maven build tool]]></category><category><![CDATA[maven integration]]></category><category><![CDATA[#Nexus]]></category><dc:creator><![CDATA[Seun B]]></dc:creator><pubDate>Thu, 10 Oct 2024 04:25:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728534140747/b381a077-57fb-4945-8f2c-268c541f2312.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In software development environment, the need for efficient artifact management is paramount. As a DevOps Engineer, I recognized the necessity of streamlining the deployment process and ensuring a reliable artifact repository for Java applications. To achieve this, I recently embarked on a journey to set up Artifactory on cloud server. In this blog, I will share the steps I took to accomplish this, detailing the installation and configuration processes along the way.</p>
<h2 id="heading-purpose">Purpose</h2>
<p>Artifactory management serve as vital components in a DevOps pipeline. They provide a centralized location to store and manage artifacts produced during the software development lifecycle. It is known for its rich feature set, including support for various package types, advanced search capabilities, and user management features.</p>
<h2 id="heading-the-situation">The Situation:</h2>
<p>As a DevOps Engineer, I once faced challenges with a team concerning dependency management and artifact storage, ultimately leading to delays in deployment when locally stored packages were accidentally deleted. The absence of a centralized repository made it difficult to track versions and manage dependencies effectively. To overcome these challenges, I decided to deploy Nexus to manage the artifacts while maven was already used in the environment to build the Java applications.</p>
<h3 id="heading-lets-start-simple-first-we-will-put-our-java-app-on-apache-tomcat-which-is-a-web-server-this-helps-us-check-if-our-app-works-right-on-a-basic-website-if-it-works-here-we-know-its-good-to-go">Let's start simple. First, we will put our Java app on Apache Tomcat, which is a web server. This helps us check if our app works right on a basic website. If it works here, we know it's good to go.</h3>
<h4 id="heading-pre-requisites-ubuntu-server-or-any-other-linux-server">Pre-requisites: Ubuntu Server or any other Linux server</h4>
<h3 id="heading-1-installing-tomcat">1. Installing Tomcat</h3>
<p><strong>Create a Tomcat User</strong></p>
<pre><code class="lang-bash">sudo useradd -m -d /opt/tomcat -U -s /bin/<span class="hljs-literal">false</span> tomcat
</code></pre>
<p><strong>Update the Linux Package Manager Cache</strong></p>
<pre><code class="lang-bash">sudo apt update
</code></pre>
<p><strong>Install Java</strong></p>
<pre><code class="lang-bash">sudo apt install openjdk-17-jdk
java -version
</code></pre>
<p><strong>Download and Install Tomcat</strong> Before downloading, confirm the latest Tomcat build package from the <a target="_blank" href="https://tomcat.apache.org/">official website</a>.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Download Tomcat</span>
<span class="hljs-built_in">cd</span> /tmp
wget https://dlcdn.apache.org/tomcat/tomcat-11/v11.0.0-M26/bin/apache-tomcat-11.0.0-M26.tar.gz

<span class="hljs-comment"># Extract Tomcat files</span>
sudo tar xzvf apache-tomcat-11*tar.gz -C /opt/tomcat --strip-components=1

<span class="hljs-comment"># Set ownership and permissions</span>
sudo chown -R tomcat:tomcat /opt/tomcat/
sudo chmod -R u+x /opt/tomcat/bin
</code></pre>
<p><strong>Configure Users for Tomcat</strong>:</p>
<ul>
<li>Edit the <code>tomcat-users.xml</code> file to define user roles and access:</li>
</ul>
<pre><code class="lang-bash">sudo nano /opt/tomcat/conf/tomcat-users.xml
</code></pre>
<p>Add the following lines before the closing <code>&lt;/tomcat-users&gt;</code> tag:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">role</span> <span class="hljs-attr">rolename</span>=<span class="hljs-string">"manager-gui"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">user</span> <span class="hljs-attr">username</span>=<span class="hljs-string">"manager"</span> <span class="hljs-attr">password</span>=<span class="hljs-string">"xxxxxxx"</span> <span class="hljs-attr">roles</span>=<span class="hljs-string">"manager-gui"</span> /&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">role</span> <span class="hljs-attr">rolename</span>=<span class="hljs-string">"admin-gui"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">user</span> <span class="hljs-attr">username</span>=<span class="hljs-string">"admin"</span> <span class="hljs-attr">password</span>=<span class="hljs-string">"xxxxxxx"</span> <span class="hljs-attr">roles</span>=<span class="hljs-string">"manager-gui,admin-gui"</span> /&gt;</span>
</code></pre>
<p><strong>Replace with your chosen password</strong></p>
<p><img src="https://github.com/user-attachments/assets/5d7dca0c-f9b1-4f5f-8b09-ced17a1331c8" alt="image" /></p>
<p><strong>Allow Remote Access</strong>:</p>
<ul>
<li>To enable access to the Manager and Host Manager pages, edit the context.xml files:</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-comment"># Edit Manager context file</span>
sudo nano /opt/tomcat/webapps/manager/META-INF/context.xml
</code></pre>
<p>Comment out the Valve definition in this file by adding arrows to the beginning and end of line. Repeat the same for the Host Manager context file:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Edit Host Manager context file</span>
sudo nano /opt/tomcat/webapps/host-manager/META-INF/context.xml
</code></pre>
<p><img src="https://github.com/user-attachments/assets/efec82b6-3dfe-4f9f-920a-40eecc230054" alt="image" /></p>
<p><strong>Setup Systemd for Tomcat</strong>:</p>
<ul>
<li>Find the Java location:</li>
</ul>
<pre><code class="lang-bash">sudo update-java-alternatives -l
</code></pre>
<p><img src="https://github.com/user-attachments/assets/cc9d2168-860a-4351-9633-32832d4a8987" alt="image" /></p>
<p>Create the <a target="_blank" href="http://java.sh"><code>java.sh</code></a> profile:</p>
<pre><code class="lang-bash">sudo nano /etc/profile.d/java.sh
<span class="hljs-comment"># Add the following lines</span>
<span class="hljs-built_in">export</span> JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
<span class="hljs-built_in">export</span> PATH=<span class="hljs-variable">$JAVA_HOME</span>/bin:<span class="hljs-variable">$PATH</span>
</code></pre>
<p>Create the <a target="_blank" href="http://setenv.sh"><code>setenv.sh</code></a> file for Tomcat:</p>
<pre><code class="lang-bash">sudo nano /opt/tomcat/bin/setenv.sh
<span class="hljs-comment"># Add the following lines</span>
<span class="hljs-built_in">export</span> JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
<span class="hljs-built_in">export</span> JRE_HOME=/usr/lib/jvm/java-17-openjdk-amd64
</code></pre>
<p><strong>Create the Tomcat Service File</strong> (to automatically start on every system reboot)</p>
<pre><code class="lang-bash">sudo nano /etc/systemd/system/tomcat.service
</code></pre>
<p>Add the following configuration:</p>
<pre><code class="lang-ini"><span class="hljs-section">[Unit]</span>
<span class="hljs-attr">Description</span>=Tomcat
<span class="hljs-attr">After</span>=network.target

<span class="hljs-section">[Service]</span>
<span class="hljs-attr">Type</span>=forking
<span class="hljs-attr">User</span>=tomcat
<span class="hljs-attr">Group</span>=tomcat

<span class="hljs-attr">Environment</span>=<span class="hljs-string">"JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64"</span>
<span class="hljs-attr">Environment</span>=<span class="hljs-string">"JAVA_OPTS=-Djava.security.egd=file:///dev/urandom"</span>
<span class="hljs-attr">Environment</span>=<span class="hljs-string">"CATALINA_BASE=/opt/tomcat"</span>
<span class="hljs-attr">Environment</span>=<span class="hljs-string">"CATALINA_HOME=/opt/tomcat"</span>
<span class="hljs-attr">Environment</span>=<span class="hljs-string">"CATALINA_PID=/opt/tomcat/temp/tomcat.pid"</span>
<span class="hljs-attr">Environment</span>=<span class="hljs-string">"CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"</span>

<span class="hljs-attr">ExecStart</span>=/opt/tomcat/bin/startup.sh
<span class="hljs-attr">ExecStop</span>=/opt/tomcat/bin/shutdown.sh

<span class="hljs-attr">RestartSec</span>=<span class="hljs-number">10</span>
<span class="hljs-attr">Restart</span>=always

<span class="hljs-section">[Install]</span>
<span class="hljs-attr">WantedBy</span>=multi-user.target
</code></pre>
<p><strong>Start Tomcat</strong></p>
<pre><code class="lang-bash">sudo systemctl daemon-reload
sudo systemctl start tomcat
sudo systemctl <span class="hljs-built_in">enable</span> tomcat
</code></pre>
<p><img src="https://github.com/user-attachments/assets/db62b67c-edf8-4445-b562-4fe15a95c29a" alt="image" /></p>
<p>Allow access to Tomcat on port 8080:</p>
<pre><code class="lang-bash">sudo ufw allow 8080
</code></pre>
<p><strong>Test Tomcat</strong> Access the Tomcat web interface by navigating to <code>http://&lt;your-server-ip&gt;:8080</code> in your web browser.</p>
<p><img src="https://github.com/user-attachments/assets/bcf21321-b5b2-4c87-8c63-a3fb4a9a8574" alt="image" /></p>
<h3 id="heading-2-downloading-and-building-your-java-application-with-maven">2. Downloading and Building Your Java Application with Maven</h3>
<p><strong>Install Maven</strong></p>
<pre><code class="lang-bash">sudo apt update
sudo apt install maven
mvn -version
</code></pre>
<p><strong>Clone A sample Application from GitHub</strong></p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /home/ubuntu
git <span class="hljs-built_in">clone</span> https://github.com/balogsun/maven-java-builds.git
</code></pre>
<p><strong>Edit the</strong> <code>pom.xml</code> File</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> maven-java-builds
</code></pre>
<p>Change the <code>&lt;finalName&gt;</code> tag in your <code>pom.xml</code> to a name of your choice and save:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">finalName</span>&gt;</span>My_Maven_Webapp<span class="hljs-tag">&lt;/<span class="hljs-name">finalName</span>&gt;</span>
</code></pre>
<p><img src="https://github.com/user-attachments/assets/964341cf-f658-4e10-b2c9-62be1421bbe5" alt="image" /></p>
<p><strong>Lets modify index.jsp file to what we would like to see on our browser when launced</strong></p>
<pre><code class="lang-bash">nano /home/ubuntu/maven-java-builds/src/main/webapp/index.jsp
</code></pre>
<p>Look for below section and change it to whatwever suits you</p>
<pre><code class="lang-bash">&lt;table border=<span class="hljs-string">"0"</span> cellpadding=<span class="hljs-string">"0"</span> cellspacing=<span class="hljs-string">"0"</span> width=<span class="hljs-string">"100%"</span> style=<span class="hljs-string">"max-width: 600px;"</span>&gt;
    &lt;tr&gt;
        &lt;td bgcolor=<span class="hljs-string">"#ffffff"</span> align=<span class="hljs-string">"center"</span> valign=<span class="hljs-string">"top"</span> style=<span class="hljs-string">"padding: 40px 20px 20px 20px; border-radius: 4px 4px 0px 0px; color: #11111
            &lt;h1 style="</span>font-size: 28px; font-weight: 400; margin: 2;<span class="hljs-string">"&gt;My Builds with Maven&lt;/h1&gt;
            &lt;img src="</span> https://img.icons8.com/clouds/100/000000/handshake.png<span class="hljs-string">" width="</span>125<span class="hljs-string">" height="</span>120<span class="hljs-string">" style="</span>display: block; border: 0px;<span class="hljs-string">"
            &lt;p style="</span>font-size:15px<span class="hljs-string">"&gt;Maven Build.&lt;/p&gt;
            &lt;p style="</span>font-size:20px<span class="hljs-string">"&gt;Cool!!!&lt;/p&gt;
        &lt;/td&gt;</span>
</code></pre>
<p><img src="https://github.com/user-attachments/assets/a6b8f849-af5a-4068-b729-f3a3fa5aa262" alt="image" /></p>
<p><strong>Build Your Application</strong></p>
<pre><code class="lang-bash">mvn package
</code></pre>
<p><strong>Deploy the WAR File to Tomcat</strong></p>
<pre><code class="lang-bash">sudo cp /home/ubuntu/maven-java-builds/target/My_Maven_Webapp.war /opt/tomcat/webapps
</code></pre>
<p>Access your application at <code>http://&lt;your-server-ip&gt;:8080/My_Maven_Webapp</code>.</p>
<p><img src="https://github.com/user-attachments/assets/637570c4-c61d-4789-a863-33f9222d8ca2" alt="image" /></p>
<h3 id="heading-3-installing-nexus-repository-manager">3. Installing Nexus Repository Manager</h3>
<p><strong>Download and Install Nexus Repository</strong></p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /opt
sudo wget https://download.sonatype.com/nexus/3/latest-unix.tar.gz
sudo tar -zxvf latest-unix.tar.gz
sudo mv nexus-3.* nexus
</code></pre>
<p><strong>Create Nexus User</strong></p>
<pre><code class="lang-bash">sudo adduser nexus
sudo <span class="hljs-built_in">echo</span> <span class="hljs-string">'nexus ALL=(ALL) NOPASSWD: ALL'</span> &gt;&gt; /etc/sudoers
</code></pre>
<p><strong>Change Ownership</strong></p>
<pre><code class="lang-bash">sudo chown -R nexus:nexus /opt/nexus
sudo chown -R nexus:nexus /opt/sonatype-work
</code></pre>
<p><strong>Configure Nexus to Run as a Service</strong>:</p>
<ul>
<li>Edit the <code>nexus.rc</code> file:</li>
</ul>
<pre><code class="lang-bash">sudo nano /opt/nexus/bin/nexus.rc
<span class="hljs-comment"># Add the following line</span>
run_as_user=<span class="hljs-string">"nexus"</span>
</code></pre>
<p><strong>To modify config options, open the /opt/nexus/bin/nexus.vmoptions file, you can modify the config path as shown below</strong></p>
<pre><code class="lang-bash">sudo nano /opt/nexus/bin/nexus.vmoptions
</code></pre>
<p>In the below settings, the directory is changed from <code>../sonatype-work</code> to <code>/opt/sonatype-work</code></p>
<pre><code class="lang-bash">-Xms1024m
-Xmx1024m
-XX:MaxDirectMemorySize=1024m

-XX:LogFile=/opt/sonatype-work/nexus3/<span class="hljs-built_in">log</span>/jvm.log
-XX:-OmitStackTraceInFastThrow
-Djava.net.preferIPv4Stack=<span class="hljs-literal">true</span>
-Dkaraf.home=.
-Dkaraf.base=.
-Dkaraf.etc=etc/karaf
-Djava.util.logging.config.file=/etc/karaf/java.util.logging.properties
-Dkaraf.data=/opt/sonatype-work/nexus3
-Dkaraf.log=/opt/sonatype-work/nexus3/<span class="hljs-built_in">log</span>
-Djava.io.tmpdir=/opt/sonatype-work/nexus3/tmp
</code></pre>
<p><strong>Create a Systemd Service for Nexus</strong></p>
<pre><code class="lang-bash">sudo nano /etc/systemd/system/nexus.service
</code></pre>
<p>Add the following configuration:</p>
<pre><code class="lang-ini"><span class="hljs-section">[Unit]</span>
<span class="hljs-attr">Description</span>=nexus service
<span class="hljs-attr">After</span>=network.target

<span class="hljs-section">[Service]</span>
<span class="hljs-attr">Type</span>=forking
<span class="hljs-attr">LimitNOFILE</span>=<span class="hljs-number">65536</span>
<span class="hljs-attr">ExecStart</span>=/opt/nexus/bin/nexus start
<span class="hljs-attr">ExecStop</span>=/opt/nexus/bin/nexus stop
<span class="hljs-attr">User</span>=nexus
<span class="hljs-attr">Restart</span>=<span class="hljs-literal">on</span>-abort

<span class="hljs-section">[Install]</span>
<span class="hljs-attr">WantedBy</span>=multi-user.target
</code></pre>
<p><strong>Start Nexus</strong></p>
<pre><code class="lang-bash">sudo systemctl start nexus
sudo systemctl <span class="hljs-built_in">enable</span> nexus
sudo systemctl status nexus
</code></pre>
<p>Allow access to Nexus on port 8081:</p>
<pre><code class="lang-bash">sudo ufw allow 8081/tcp
</code></pre>
<p><strong>Access Nexus Web Interface</strong> Navigate to <code>http://&lt;your-server-ip&gt;:8081</code> in your web browser.</p>
<p><strong>Login to Nexus</strong></p>
<ol>
<li><p>Use the default credentials:</p>
<ul>
<li><p>Username: <code>admin</code></p>
</li>
<li><p>Password: (this password is generated during the installation; find it in the file <code>/opt/nexus/sonatype-work/nexus3/admin.password</code>).</p>
</li>
</ul>
</li>
</ol>
<p><img src="https://github.com/user-attachments/assets/19ea0fe1-67a4-4259-82a9-0c6dc6e8a237" alt="image" /></p>
<p><strong>Change the Admin Password</strong></p>
<p>You will be prompted to change the password upon first login.</p>
<h3 id="heading-4-creating-repositories-in-nexus">4. Creating Repositories in Nexus</h3>
<p><strong>Create a Maven Hosted Repository</strong></p>
<ol>
<li><p>In the Nexus web interface, click on <strong>wheel-like icon</strong>.</p>
</li>
<li><p>Click on <code>repository</code> and <strong>Create repository</strong>.</p>
</li>
<li><h2 id="heading-select-maven2-hosted-and-click-next">Select <strong>maven2 (hosted)</strong> and click <strong>Next</strong>.</h2>
<p> <img src="https://github.com/user-attachments/assets/cd16b958-8de4-43d3-bb26-fbe342c9b5b6" alt="image" /></p>
</li>
<li><p>Configure the repository settings (like name, version policy, etc.), and click <strong>Create repository</strong>.</p>
</li>
<li><p>Configure the repository settings, and click <strong>Create repository</strong>.</p>
</li>
</ol>
<h3 id="heading-test-a-manual-upload-to-artifactory">Test a manual upload to artifactory.</h3>
<p>First get the url of your repository and copy it out for the next coomand below</p>
<p><img src="https://github.com/user-attachments/assets/42dea90b-2fab-4cb0-9fe5-63fd8860c5ad" alt="image" /></p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /home/ubuntu/maven-java-builds/target
curl -v -u admin:pass --upload-file /root/maven-java-builds/target/My_Maven_Webapp.war http://&lt;server-ip-address&gt;:8081/repository/My_Maven_Webapp/
</code></pre>
<p><img src="https://github.com/user-attachments/assets/caf6f7b4-f964-42cf-aace-b4b71dcc80e6" alt="image" /></p>
<ul>
<li><p>Check back at your repository in the <code>browse section</code> to find you artifacts uploaded.</p>
</li>
<li><p>Likewise, artifacts can also be donwloaded manually.</p>
</li>
</ul>
<pre><code class="lang-bash">curl -X GET http://admin:pass@&lt;server-ip-address&gt;:8081/repository/My_Maven_Webapp/My_Maven_Webapp.war --output My_Maven_Webapp.war
</code></pre>
<h3 id="heading-integrating-nexus-with-maven-builds">Integrating Nexus with Maven Builds</h3>
<h2 id="heading-lets-configure-your-maven-project-to-work-with-nexus">Let's configure your Maven project to work with Nexus.</h2>
<ul>
<li>Navigate to your project directory:</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /home/ubuntu/maven-java-builds
</code></pre>
<h3 id="heading-configuring-pomxml">Configuring pom.xml</h3>
<p>Your <code>pom.xml</code> file is the heart of your Maven project. Here's a sample configuration:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://maven.apache.org/POM/4.0.0"</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span>
  <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>myapp<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>My_Maven_Webapp<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">packaging</span>&gt;</span>war<span class="hljs-tag">&lt;/<span class="hljs-name">packaging</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>My sample Maven Webapp<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">url</span>&gt;</span>http://maven.apache.org<span class="hljs-tag">&lt;/<span class="hljs-name">url</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Properties for Java version and encoding --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">maven.compiler.release</span>&gt;</span>17<span class="hljs-tag">&lt;/<span class="hljs-name">maven.compiler.release</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">project.build.sourceEncoding</span>&gt;</span>UTF-8<span class="hljs-tag">&lt;/<span class="hljs-name">project.build.sourceEncoding</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Dependencies --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>javax.servlet<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>javax.servlet-api<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>4.0.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>provided<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Build configuration --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">finalName</span>&gt;</span>My_Maven_Webapp<span class="hljs-tag">&lt;/<span class="hljs-name">finalName</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- Compiler plugin --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.10.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">release</span>&gt;</span>17<span class="hljs-tag">&lt;/<span class="hljs-name">release</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- WAR plugin --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>maven-war-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.3.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- Deploy plugin --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>maven-deploy-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.1.0<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Distribution Management for Nexus --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">distributionManagement</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">repository</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>nexus<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>My_Maven_Webapp<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">url</span>&gt;</span>http://<span class="hljs-tag">&lt;<span class="hljs-name">Ip-address</span>&gt;</span>:8081/repository/My_Maven_Webapp/<span class="hljs-tag">&lt;/<span class="hljs-name">url</span>&gt;</span> <span class="hljs-comment">&lt;!-- Your repository URL here --&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">repository</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">distributionManagement</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span>
</code></pre>
<h2 id="heading-setting-up-nexus">Setting Up Nexus</h2>
<p>Configure Maven to use Nexus by creating a <code>settings.xml</code> file:</p>
<pre><code class="lang-bash">mkdir -p ~/.m2 (this should already exist following initial deploymenets)
sudo nano ~/.m2/settings.xml
</code></pre>
<p>Add the following content:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">settings</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://maven.apache.org/SETTINGS/1.0.0"</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">"http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">servers</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">server</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>nexus<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">username</span>&gt;</span>username<span class="hljs-tag">&lt;/<span class="hljs-name">username</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">password</span>&gt;</span>password<span class="hljs-tag">&lt;/<span class="hljs-name">password</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">server</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">servers</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">settings</span>&gt;</span>
</code></pre>
<p>Ensure proper permissions:</p>
<pre><code class="lang-bash">chmod 755 ~/.m2/settings.xml
chown username:groupname ~/.m2/settings.xml
</code></pre>
<h2 id="heading-deploying-your-application">Deploying Your Application</h2>
<p>To deploy your application to Nexus, run:</p>
<pre><code class="lang-bash">mvn clean deploy
</code></pre>
<p>This command will compile your code, run tests, package your application, and upload it to Nexus.</p>
<p><img src="https://github.com/user-attachments/assets/a1922b90-13de-418c-b6c5-7c4e52e7a7e7" alt="image" /></p>
<h2 id="heading-check-back-at-your-repository-and-find-the-newly-uploaded-artifacts">Check back at your repository and find the newly uploaded artifacts</h2>
<p><img src="https://github.com/user-attachments/assets/f8f52ece-a2be-440d-9d35-6324aee8c789" alt="image" /></p>
<h2 id="heading-updating-your-application">Updating Your Application</h2>
<p>To update your application:</p>
<ol>
<li><p>Modify your <code>pom.xml</code> to increment the version number.</p>
</li>
<li><p>Update your application code as needed.</p>
</li>
<li><p>Run <code>mvn clean deploy</code> again to deploy the new version.</p>
</li>
</ol>
<h2 id="heading-troubleshooting">Troubleshooting</h2>
<p>If you encounter a 401 Unauthorized error, ensure that:</p>
<ol>
<li><p>Your <code>settings.xml</code> is in the correct location (<code>~/.m2/settings.xml</code> or <code>/root/.m2/settings.xml</code> if running as root).</p>
</li>
<li><p>The credentials in <code>settings.xml</code> match those in your Nexus server.</p>
</li>
</ol>
<h2 id="heading-java-compatibility">Java Compatibility</h2>
<p>Ensure you're using Java 17 or later to set up your environment:</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>With these detailed steps, you would have successfully accomplished three key objectives: setting up Tomcat, deploying a Java application, and integrating Nexus Repository into the workflow. This process not only streamlines the development process but will also enhance collaboration within a team. The ability to manage dependencies efficiently and deploy applications reliably will definitely increase one's confidence in delivering high-quality software on time. Furthermore, these manual builds can be integrated into CI/CD pipelines, for full automation. Overall, this implementation significantly improves development lifecycle, positioning a team for more efficient and effective project execution.</p>
]]></content:encoded></item><item><title><![CDATA[The Secret Life of APIs: Connecting Apps and Services Like a Pro]]></title><description><![CDATA[🌐 Ever Wondered How Apps and Services Work Together?
Think of APIs (Application Programming Interfaces) as the secret sauce behind seamless interactions between different apps and services. They’re like the unsung heroes that keep everything connect...]]></description><link>https://devblog.seunb.com/the-secret-life-of-apis-connecting-apps-and-services-like-a-pro</link><guid isPermaLink="true">https://devblog.seunb.com/the-secret-life-of-apis-connecting-apps-and-services-like-a-pro</guid><category><![CDATA[APIs]]></category><category><![CDATA[Devops]]></category><category><![CDATA[beginnersguide]]></category><category><![CDATA[Cloud]]></category><dc:creator><![CDATA[Seun B]]></dc:creator><pubDate>Fri, 13 Sep 2024 04:59:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726203415552/6380d18c-6e72-451d-a469-d194c37b43f3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-ever-wondered-how-apps-and-services-work-together">🌐 <strong>Ever Wondered How Apps and Services Work Together?</strong></h3>
<p>Think of <strong>APIs</strong> (Application Programming Interfaces) as the secret sauce behind seamless interactions between different apps and services. They’re like the unsung heroes that keep everything connected, whether it’s pulling in social media feeds or checking the weather.</p>
<h3 id="heading-whats-an-api-gateway-anyway">🚦 <strong>What’s an API Gateway, Anyway?</strong></h3>
<p>Imagine an <strong>API Gateway</strong> as the <strong>traffic manager</strong> for your data. It’s the hub where all API requests pass through, ensuring they’re handled efficiently. This gateway takes care of important tasks like security, routing requests, and even translating data formats so that everything runs smoothly.</p>
<h3 id="heading-lets-break-down-apis">🍽️ <strong>Let’s Break Down APIs</strong></h3>
<p>Picture this scenario:</p>
<ul>
<li><p>You (the client) make a request to a waiter (the API) for something on the menu.</p>
</li>
<li><p>The waiter takes your order to the kitchen (the system) and gets your meal (the response) prepared.</p>
</li>
<li><p>The waiter then delivers the meal back to you.</p>
</li>
</ul>
<p>That’s the essence of an API, facilitating communication between systems and delivering the right information.</p>
<h3 id="heading-what-about-api-requests">📲 <strong>What About API Requests?</strong></h3>
<p>An <strong>API Request</strong> is like making an order at your favorite restaurant. When you use an app to check the weather, for instance:</p>
<ul>
<li><p>Your phone sends a request to the weather service via the API.</p>
</li>
<li><p>This request specifies what you need (like the temperature or forecast) and includes any necessary authentication details.</p>
</li>
</ul>
<p>The service processes your request and sends back the information you asked for in an <strong>API response</strong>.</p>
<h3 id="heading-real-world-example-ordering-pizza-with-an-app">🍕 <strong>Real-World Example: Ordering Pizza with an App</strong></h3>
<p>Think of a food delivery app, like Uber Eats:</p>
<ol>
<li><p><strong>Multiple APIs at Work</strong>:</p>
<ul>
<li><p><strong>User API</strong> for your account info.</p>
</li>
<li><p><strong>Restaurant API</strong> for listing restaurants.</p>
</li>
<li><p><strong>Payment API</strong> for processing transactions.</p>
</li>
<li><p><strong>Delivery API</strong> for tracking your order.</p>
</li>
</ul>
</li>
<li><p><strong>How the API Gateway Fits In</strong>:</p>
<ul>
<li><p><strong>Central Hub</strong>: Instead of each service interacting directly with the app, all requests go through the API Gateway.</p>
</li>
<li><p><strong>Routing</strong>: The Gateway directs requests to the appropriate service, like User or Payment APIs.</p>
</li>
<li><p><strong>Security</strong>: Manages authentication and permissions.</p>
</li>
<li><p><strong>Traffic Control</strong>: Balances request flow to prevent overload.</p>
</li>
<li><p><strong>Data Transformation</strong>: Ensures data is in the right format for each service.</p>
</li>
<li><p><strong>Response Aggregation</strong>: Collects responses from different services and sends a unified update back to the app.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-why-an-api-gateway-matters">🔍 <strong>Why an API Gateway Matters</strong></h3>
<ul>
<li><p><strong>Streamlines Requests</strong>: Centralizes the process, making it simpler and more efficient.</p>
</li>
<li><p><strong>Enhances Security</strong>: Manages access control and authentication.</p>
</li>
<li><p><strong>Controls Traffic</strong>: Prevents any one service from getting overwhelmed by requests.</p>
</li>
<li><p><strong>Monitors Performance</strong>: Provides insights and tracking for better troubleshooting.</p>
</li>
</ul>
<p>APIs and API Gateways might not always be in the spotlight, but they’re essential for the smooth operation of today’s tech landscape.</p>
]]></content:encoded></item><item><title><![CDATA[Self-Healing and Monitoring: A comprehensive guide to revolutionizing System Resilience Through Automation]]></title><description><![CDATA[In today’s fast-paced digital world, maintaining system reliability and minimizing downtime are critical for business success. This comprehensive guide explores how to enhance system resilience through advanced monitoring and self-healing mechanisms....]]></description><link>https://devblog.seunb.com/self-healing-and-monitoring-a-comprehensive-guide-to-revolutionizing-system-resilience-through-automation</link><guid isPermaLink="true">https://devblog.seunb.com/self-healing-and-monitoring-a-comprehensive-guide-to-revolutionizing-system-resilience-through-automation</guid><category><![CDATA[self healing technology]]></category><category><![CDATA[Datadog]]></category><category><![CDATA[monitoring]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Seun B]]></dc:creator><pubDate>Mon, 02 Sep 2024 14:02:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724734564957/5c70e14d-4e64-41c1-b088-93a883dc46ab.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today’s fast-paced digital world, maintaining system reliability and minimizing downtime are critical for business success. This comprehensive guide explores how to enhance system resilience through advanced monitoring and self-healing mechanisms.</p>
<p>We will walk you through integrating Datadog for monitoring, setting up automated recovery scripts, and leveraging Node.js and webhooks to create a reliable self-healing system (with a focus on disk management).</p>
<p>By the end of this guide, you'll have a fully automated setup that can proactively manage system issues, ensuring smooth and uninterrupted operations.</p>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<ul>
<li><p><strong>A Datadog Account</strong>: Create an active Datadog account for monitoring and alerts.</p>
</li>
<li><p><strong>A Linux Server</strong>: This can be either on-premises or a cloud-based instance.</p>
</li>
<li><p><strong>Internet Access</strong>: Required for installing software, setting up integrations, and accessing Datadog.</p>
</li>
</ul>
<h3 id="heading-1-create-a-datadog-account"><strong>1. Create a Datadog Account</strong></h3>
<ol>
<li><p><strong>Sign Up for Datadog</strong>:</p>
<ul>
<li><p>Visit <a target="_blank" href="https://www.datadoghq.com/">Datadog's sign-up page</a> and create a <code>free trial</code> account by entering your email and setting a password.</p>
</li>
<li><p>Complete the registration process, create a name for your <code>organization</code>, and verify your email if required.</p>
</li>
<li><p>Log in to your Datadog dashboard.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-2-deploy-your-first-datadog-agent"><strong>2. Deploy Your First Datadog Agent</strong></h3>
<p>Guides to install on your preferred operating system are listed in the <code>integration</code> --&gt; <code>agents</code> section.</p>
<h4 id="heading-for-a-local-ubuntu-server"><strong>For a Local Ubuntu Server:</strong></h4>
<ol>
<li><p><strong>Install the Datadog Agent</strong>:</p>
<ul>
<li><p><strong>Obtain Your Datadog API Key</strong>:</p>
<ul>
<li>Navigate to <strong>Organization settings</strong> &gt; <strong>API Keys</strong> to find your API key.</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>    <img src="https://github.com/user-attachments/assets/dbcdd80d-d48b-4339-86e9-204ba16a7836" alt="image" /></p>
<p>    <img src="https://github.com/user-attachments/assets/c26f2caa-9c90-424d-94b9-54cedb6c5557" alt="image" /></p>
<ul>
<li><p><strong>Install the Agent</strong>:</p>
<ul>
<li><p>Run the following command on your Ubuntu server to install the Datadog Agent:</p>
<pre><code class="lang-bash">  DD_API_KEY=8axxxxxxxxxxxxxxxxxxxxxxxxxxxf43 DD_SITE=<span class="hljs-string">"datadoghq.com"</span> bash -c <span class="hljs-string">"<span class="hljs-subst">$(curl -L https://install.datadoghq.com/scripts/install_script_agent7.sh)</span>"</span>
</code></pre>
</li>
</ul>
</li>
</ul>
<p>    <img src="https://github.com/user-attachments/assets/43ed04b5-cda0-400b-8c6c-5044322ba2c4" alt="image" /></p>
<ul>
<li>This command sets up the agent and automatically configures it with your API key.</li>
</ul>
<ol start="2">
<li><p><strong>Verify Agent Installation</strong>:</p>
<ul>
<li><p>Check the agent status to ensure it is running:</p>
<pre><code class="lang-bash">  systemctl status datadog-agent
  sudo datadog-agent status
</code></pre>
</li>
<li><p>You should see output indicating that the agent is running and sending data.</p>
<p>  <img src="https://github.com/user-attachments/assets/7589f5b1-0761-4ea3-b227-468337853cfe" alt="image" /></p>
</li>
<li><p>To check logs, use:</p>
<pre><code class="lang-bash">  tail -f /var/<span class="hljs-built_in">log</span>/datadog/agent.log
</code></pre>
</li>
</ul>
</li>
</ol>
<h4 id="heading-for-ubuntu-server-managing-a-kubernetes-cluster-with-kubectl-and-helm-already-installed"><strong>For Ubuntu Server Managing a Kubernetes Cluster with</strong> <code>kubectl</code> and <code>helm</code> already installed:</h4>
<ol>
<li><p><strong>Create a Datadog API Key Secret</strong>:</p>
<ul>
<li><p>Execute the following command to create a Kubernetes secret containing your Datadog API key:</p>
<pre><code class="lang-bash">  kubectl create secret generic datadog-secret --from-literal api-key=8axxxxxxxxxxxxxxxxxxxxxxxxxxxf43
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Deploy the Datadog Agent in the Cluster</strong>:</p>
<ul>
<li><p>Add the Datadog Helm repository and update:</p>
<pre><code class="lang-bash">  curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
  chmod 700 get_helm.sh
  ./get_helm.sh

  helm repo add datadog https://helm.datadoghq.com
  helm repo update
</code></pre>
</li>
<li><p>Create and configure <code>datadog-values.yaml</code>:</p>
<pre><code class="lang-bash">  nano datadog-values.yaml
</code></pre>
<p>  Add the following content:</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">datadog:</span>
    <span class="hljs-attr">apiKeyExistingSecret:</span> <span class="hljs-string">datadog-secret</span>
</code></pre>
</li>
<li><p>Deploy the Datadog Agent:</p>
<pre><code class="lang-bash">  helm install datadog-agent -f datadog-values.yaml datadog/datadog
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/dcda0e71-4f88-47b6-8efc-98ceebbf8c09" alt="image" /></p>
</li>
<li><p>Confirm agents are running:</p>
<pre><code class="lang-bash">  kubectl get all
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/c051b027-075f-4815-9875-2e81bb8d93b1" alt="image" /></p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-3-prepare-a-disk-for-monitoring"><strong>3. Prepare a Disk for Monitoring</strong></h3>
<p>An alert will be triggered when the disk capacity reaches a determined threshold.</p>
<ol>
<li><p><strong>Add a New Disk to the Server</strong>:</p>
<ul>
<li>In your VMware or AWS cloud instance, add a new 2GB disk.</li>
</ul>
</li>
</ol>
<h4 id="heading-adding-a-2gb-disk-in-vmware-workstation"><strong>Adding a 2GB Disk in VMware Workstation</strong></h4>
<ol>
<li><p><strong>Open VMware Workstation</strong>:</p>
<ul>
<li>Launch VMware Workstation and select your virtual machine.</li>
</ul>
</li>
<li><p><strong>Open VM Settings</strong>:</p>
<ul>
<li><p>Right-click on the virtual machine and select <strong>Settings</strong>.</p>
<p>  <img src="https://github.com/user-attachments/assets/4742ad6b-9623-4909-a15c-34da72c78046" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>Add a New Disk</strong>:</p>
<ul>
<li><p>Click <strong>Add</strong> to open the <strong>Add Hardware Wizard</strong>.</p>
</li>
<li><p>Choose <strong>Hard Disk</strong> and click <strong>Next</strong>.</p>
</li>
<li><p>Select <strong>SCSI</strong> (recommended) or <strong>IDE</strong> and click <strong>Next</strong>.</p>
</li>
<li><p>Choose <strong>Create a new virtual disk</strong> and click <strong>Next</strong>.</p>
</li>
<li><p>Specify the disk size as <strong>2 GB</strong>.</p>
</li>
<li><p>Choose the location to store the virtual disk file and click <strong>Next</strong>.</p>
</li>
<li><p>Click <strong>Finish</strong> to create the disk.</p>
</li>
</ul>
</li>
</ol>
<h4 id="heading-adding-a-2gb-disk-in-aws"><strong>Adding a 2GB Disk in AWS</strong></h4>
<ol>
<li><p><strong>Log in to AWS Management Console</strong>:</p>
<ul>
<li><p>Navigate to <a target="_blank" href="https://aws.amazon.com/console/">AWS Management Console</a>.</p>
</li>
<li><p>Log in with your credentials.</p>
</li>
</ul>
</li>
<li><p><strong>Navigate to EC2 Dashboard</strong>:</p>
<ul>
<li>Go to <strong>Services</strong> &gt; <strong>EC2</strong>.</li>
</ul>
</li>
<li><p><strong>Create a New EBS Volume</strong>:</p>
<ul>
<li><p>In the left sidebar, click on <strong>Volumes</strong> under <strong>Elastic Block Store</strong>.</p>
</li>
<li><p>Click <strong>Create Volume</strong>.</p>
</li>
<li><p>Configure the volume:</p>
<ul>
<li><p><strong>Volume Type</strong>: Choose <code>General Purpose SSD (gp3)</code>, <code>Provisioned IOPS SSD (io1)</code>, etc.</p>
</li>
<li><p><strong>Size</strong>: Enter <strong>2 GiB</strong>.</p>
</li>
<li><p><strong>Availability Zone</strong>: Select the same availability zone as your EC2 instance.</p>
</li>
</ul>
</li>
<li><p>Click <strong>Create Volume</strong>.</p>
<p>  <img src="https://github.com/user-attachments/assets/993071f4-9505-4357-8259-a74ca1c03c97" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>Attach the EBS Volume to an EC2 Instance</strong>:</p>
<ul>
<li><p>Go back to <strong>Volumes</strong>.</p>
</li>
<li><p>Select the volume you created.</p>
</li>
<li><p>Click <strong>Actions</strong> &gt; <strong>Attach Volume</strong>.</p>
</li>
<li><p>Choose the instance you want to attach the volume to from the drop-down list.</p>
</li>
<li><p>Click <strong>Attach</strong>.</p>
</li>
</ul>
</li>
<li><p><strong>Log in to Your EC2 or VMware Instance</strong>.</p>
</li>
<li><p><strong>Prepare the Volume for Use</strong>:</p>
<ul>
<li><p><strong>Verify Disk</strong>:</p>
<pre><code class="lang-bash">  lsblk
</code></pre>
<p>  The new disk should be listed as <code>/dev/xvdf</code> or similar.</p>
<p>  <img src="https://github.com/user-attachments/assets/b0c66092-c256-40b4-b157-ee9ee0697f1f" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>Install LVM</strong>: LVM (Logical Volume Management) is used to manage disk volumes because it offers flexibility, efficiency, and scalability. It allows dynamic resizing of partitions, easy addition and removal of disks, and improved storage utilization through aggregation and thin provisioning. LVM enhances performance with striping, supports snapshots for backups, simplifies administration, and can be combined with mirroring or RAID for high availability, making it an ideal choice for environments with dynamic storage needs.</p>
<ul>
<li><p>Install LVM tools:</p>
<pre><code class="lang-bash">  sudo apt update
  sudo apt install -y lvm2
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Set Up LVM</strong>:</p>
<ul>
<li><p>Create a Physical Volume (PV):</p>
<pre><code class="lang-bash">  sudo pvcreate /dev/sdb
</code></pre>
</li>
<li><p>Create a Volume Group (VG):</p>
<pre><code class="lang-bash">  sudo vgcreate demoVG /dev/sdb
</code></pre>
</li>
<li><p>Create a Logical Volume (LV) using all available space:</p>
<pre><code class="lang-bash">  sudo lvcreate -n demoLV -l 100%FREE demoVG
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Format and Mount the Logical Volume</strong>:</p>
<ul>
<li><p>Format the LV with ext4 filesystem:</p>
<pre><code class="lang-bash">  sudo mkfs.ext4 /dev/demoVG/demoLV
</code></pre>
</li>
<li><p>Create a mount point and mount the LV:</p>
<pre><code class="lang-bash">  sudo mkdir /demo
  sudo mount /dev/demoVG/demoLV /demo
</code></pre>
</li>
<li><p><strong>Verify the Mount</strong>:</p>
<pre><code class="lang-bash">  df -h /demo
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/d637cd74-f4ea-4446-8575-2e269778aa09" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>Configure Automatic Mounting</strong>:</p>
<ul>
<li><p>Add the following entry to <code>/etc/fstab</code> for automatic mounting at boot:</p>
<pre><code class="lang-bash">  <span class="hljs-built_in">echo</span> <span class="hljs-string">'/dev/demoVG/demoLV /demo ext4 defaults 0 2'</span> | sudo tee -a /etc/fstab
</code></pre>
</li>
<li><p><strong>Verify fstab Configuration</strong>:</p>
<pre><code class="lang-bash">  cat /etc/fstab
</code></pre>
</li>
</ul>
</li>
</ol>
<h3 id="heading-4-set-up-the-webhook-https-listener-using-nodejs"><strong>4. Set Up the Webhook HTTPS Listener Using Node.js</strong></h3>
<p>If you prefer not to use Node.js, you may explore python Flask service, or Datadog’s serverless functions (if using a cloud provider like AWS) to trigger the script directly via AWS Lambda or an equivalent service, but the below method gives direct control on the infrastructure.</p>
<p>**First create the script, that would be triggered by Datadog’s Webhook Integration that clears/move log files in <code>/demo</code> directory**.</p>
<p><strong>Example script (</strong><code>purge_</code><a target="_blank" href="http://demo.sh"><code>demo.sh</code></a>):</p>
<pre><code class="lang-bash">nano /tmp/purge_demo.sh
</code></pre>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

LOGFILE=<span class="hljs-string">"/tmp/purge_demo.log"</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Running purge script at <span class="hljs-subst">$(date)</span>"</span> &gt;&gt; <span class="hljs-variable">$LOGFILE</span>

<span class="hljs-comment"># Directory to purge</span>
TARGET_DIR=<span class="hljs-string">"/demo"</span>

<span class="hljs-comment"># Check if the directory exists</span>
<span class="hljs-keyword">if</span> [ -d <span class="hljs-string">"<span class="hljs-variable">$TARGET_DIR</span>"</span> ]; <span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Purging all files in <span class="hljs-variable">$TARGET_DIR</span>..."</span> &gt;&gt; <span class="hljs-variable">$LOGFILE</span>
    rm -rf <span class="hljs-variable">${TARGET_DIR}</span>/* &gt;&gt; <span class="hljs-variable">$LOGFILE</span> 2&gt;&amp;1
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"All files in <span class="hljs-variable">$TARGET_DIR</span> have been purged."</span> &gt;&gt; <span class="hljs-variable">$LOGFILE</span>
<span class="hljs-keyword">else</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Directory <span class="hljs-variable">$TARGET_DIR</span> does not exist."</span> &gt;&gt; <span class="hljs-variable">$LOGFILE</span>
<span class="hljs-keyword">fi</span>
</code></pre>
<ul>
<li><p><strong>Make the Script Executable</strong>:</p>
<pre><code class="lang-bash">  chmod +x /path/to/purge_demo.sh
</code></pre>
</li>
</ul>
<ol>
<li><p><strong>Install Node.js</strong>:</p>
<ul>
<li><p>Install the Node.js package repository and Node.js:</p>
<pre><code class="lang-bash">  curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
  sudo apt install -y nodejs
</code></pre>
</li>
<li><p><strong>Verify Installation</strong>:</p>
<pre><code class="lang-bash">  node -v
  npm -v
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/3cedf108-f727-4986-9c60-27decf46f12e" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>Create a Simple Node.js Webhook Listener</strong>:</p>
<ul>
<li><p>Create a directory for the webhook listener and navigate to it:</p>
<pre><code class="lang-bash">  mkdir ~/webhook_listener
  <span class="hljs-built_in">cd</span> ~/webhook_listener
</code></pre>
</li>
<li><p>Initialize a new Node.js project:</p>
<pre><code class="lang-bash">  npm init -y
</code></pre>
</li>
<li><p>Install Express:</p>
<pre><code class="lang-bash">  npm install express
</code></pre>
</li>
<li><p>Create the <code>webhook_listener.js</code> file:</p>
<pre><code class="lang-bash">  nano webhook_listener.js
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/494ce355-c1a1-4a94-92a6-68fdf0f97a8c" alt="image" /></p>
<ul>
<li><p>Add the following code to <code>webhook_listener.js</code>:</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
  <span class="hljs-keyword">const</span> { exec } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'child_process'</span>);

  <span class="hljs-keyword">const</span> app = express();
  <span class="hljs-keyword">const</span> port = <span class="hljs-number">6060</span>;

  app.post(<span class="hljs-string">'/purge'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
      <span class="hljs-comment">// Execute the purge script</span>
      exec(<span class="hljs-string">'/tmp/purge_demo.sh'</span>, <span class="hljs-function">(<span class="hljs-params">error, stdout, stderr</span>) =&gt;</span> {
          <span class="hljs-keyword">if</span> (error) {
              <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Error executing script: <span class="hljs-subst">${error.message}</span>`</span>);
              res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">'Internal Server Error'</span>);
              <span class="hljs-keyword">return</span>;
          }
          <span class="hljs-keyword">if</span> (stderr) {
              <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Script stderr: <span class="hljs-subst">${stderr}</span>`</span>);
          }
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Script output: <span class="hljs-subst">${stdout}</span>`</span>);
          res.send(<span class="hljs-string">'Purge script executed'</span>);
      });
  });

  app.listen(port, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Webhook listener running at http://localhost:<span class="hljs-subst">${port}</span>`</span>);
  });
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/a63ad15f-795c-4f7e-bb92-c6a001abd848" alt="image" /></p>
</li>
</ul>
</li>
<li><p>The service will be actively listening for incoming HTTP POST requests on port 6060. When Datadog triggers the webhook, it will send an HTTP or HTTPS POST request to this specific URL. This request will prompt the execution of the purge script.</p>
</li>
</ul>
</li>
<li><p><strong>Make the Listener Persistent with PM2</strong> (the service will continuously run in background):</p>
<ul>
<li><p>Install PM2:</p>
<pre><code class="lang-bash">  sudo npm install -g pm2
</code></pre>
</li>
<li><p>Start the webhook listener with PM2:</p>
<pre><code class="lang-bash">  pm2 start webhook_listener.js
</code></pre>
</li>
<li><p><strong>Verify PM2 Process</strong>:</p>
<pre><code class="lang-bash">  pm2 list
  pm2 stop webhook_listener.js
  pm2 restart webhook_listener.js
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/1b862e50-8224-4f86-aeb8-3b23e65352e5" alt="image" /></p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-step-4-test-the-webhook-listener"><strong>Step 4: Test the Webhook Listener</strong></h3>
<ol>
<li><p><strong>Simulate a Webhook Request:</strong></p>
<p> You can use <code>curl</code> to simulate a POST request to your webhook:</p>
<pre><code class="lang-bash"> curl -X POST http://localhost:6060/purge
</code></pre>
<p> <img src="https://github.com/user-attachments/assets/6d7e4276-64b9-4d59-b893-3b091da55fe0" alt="image" /></p>
<p> If everything is set up correctly, the Node.js script should execute <code>/tmp/purge_</code><a target="_blank" href="http://demo.sh"><code>demo.sh</code></a> and return a confirmation message.</p>
</li>
</ol>
<h3 id="heading-5-optional-expose-the-local-server-with-a-vpn-tunnel-just-in-case-it-is-not-a-linux-cloud-instance-it-will-need-a-temporary-internet-access-through-a-vpn-tunnel"><strong>5. [Optional] Expose the Local Server with a VPN Tunnel</strong>, Just in case it is not a Linux cloud instance, it will need a temporary internet access through a vpn tunnel.</h3>
<ol>
<li><p><strong>Install Localtunnel</strong>:</p>
<ul>
<li><p>Install Localtunnel:</p>
<pre><code class="lang-bash">  sudo npm install -g localtunnel
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Start a Tunnel</strong>:</p>
<ul>
<li><p>Start a Localtunnel to expose your local webhook listener:</p>
<pre><code class="lang-bash">  lt --port 6060 --subdomain trigger-xxxx
</code></pre>
</li>
<li><p>This screen output URL will look like <a target="_blank" href="https://trigger-xxxx.loca.lt"><code>https://trigger-xxxx.loca.lt</code></a>.</p>
</li>
</ul>
</li>
<li><p><strong>Get Tunnel Password</strong>:</p>
<ul>
<li><p>Access the tunnel password (if needed) for first-time access:</p>
</li>
<li><p>Open the URL in a browser and you may be requested to enter the tunnel password.</p>
<pre><code class="lang-bash">  wget -q -O - https://loca.lt/mytunnelpassword
</code></pre>
</li>
<li><p>The private IP displayed will be your password.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-6-configure-datadog-webhook"><strong>6. Configure Datadog Webhook</strong></h3>
<ol>
<li><p><strong>Create a Webhook in Datadog</strong>:</p>
<ul>
<li><p>Log in to Datadog and navigate to <strong>Integrations</strong> &gt; Search for <strong>Webhooks</strong>.</p>
</li>
<li><p>Click <strong>New Webhook</strong> and configure it:</p>
<ul>
<li><p><strong>Name</strong>: <code>Run_Purge_Script</code></p>
</li>
<li><p><strong>URL</strong>: <a target="_blank" href="https://trigger-xxxxx.loca.lt/purge"><code>https://trigger-xxxxx.loca.lt/purge</code></a> #for tunnel URL</p>
</li>
<li><p>OR</p>
</li>
<li><p><strong>URL</strong>: <a target="_blank" href="https://server_domainIP/purge"><code>https://server_domainIP/purge</code></a> #for cloud instance</p>
</li>
<li><p><strong>Additional Options</strong>: Set as needed. [optional]</p>
</li>
</ul>
</li>
<li><p>Click <strong>Save</strong>.</p>
<p>  <img src="https://github.com/user-attachments/assets/b74dde66-c30d-435e-ad65-4fd78c23623c" alt="image" /></p>
<p>  <img src="https://github.com/user-attachments/assets/24ea75c5-008c-4cc1-86fe-963d3c425d13" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>Test that datadog can send a POST test request and Set Up a Datadog Monitor to Trigger the Webhook</strong>:</p>
<ul>
<li><p>On the monitoring page, navigate to <code>synthetic monitoring and testing</code> &gt; <code>New Test</code>.</p>
</li>
<li><p>Click <code>New API test</code>, <code>HTTP</code>, <code>URL: POST</code>, <a target="_blank" href="https://server_domainIP/purge"><code>https://server_domainIP/purge</code></a>, &gt; <code>send</code>.</p>
</li>
<li><p>You should get a success response as the screenshot below</p>
</li>
</ul>
</li>
</ol>
<p>    <img src="https://github.com/user-attachments/assets/fcfcb04d-96ba-4238-ae20-28d04774bc4c" alt="image" /></p>
<ul>
<li><p>Create a Monitor:</p>
<ul>
<li><p>Navigate to Infrastructure in Datadog page.</p>
</li>
<li><p>Hover your mouse on the host and click on <code>view host dashboard</code></p>
<p>  <img src="https://github.com/user-attachments/assets/dad3b193-3d29-4384-bba8-06645c2f8f48" alt="image" /></p>
</li>
<li><p>A graphic display of some metrics you can monitor will be shown here.</p>
</li>
<li><p>Click on the metrics you want to monitor (e.g. <code>disk usage by device</code>), click <strong>Create Monitor</strong>.</p>
</li>
</ul>
</li>
</ul>
<p>        <img src="https://github.com/user-attachments/assets/69d31ae7-ff16-45de-9d18-8c1698580713" alt="image" /></p>
<ul>
<li><p>Configure the Monitor:</p>
<ul>
<li><p>Set the query to trigger an alert when disk usage exceeds 90%:</p>
<pre><code class="lang-bash">  max(last_5m):max:system.disk.in_use{device:/dev/mapper/demoVG-demoLV} by {device} &gt; 0.9
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/3147f7b7-ee00-4c77-8e42-630c31195322" alt="image" /></p>
</li>
<li><p>Set the alert message:</p>
<pre><code class="lang-vbnet">  Alert: Disk usage on /demo has exceeded 90%. Triggering purge script.
</code></pre>
</li>
<li><p>Add recipients:</p>
<pre><code class="lang-less">  <span class="hljs-variable">@your_email</span><span class="hljs-variable">@domain</span>.com <span class="hljs-variable">@webhook-Run_Purge_Script</span>
</code></pre>
<p>  Here, your webhook will also be a recipient, by simply typing the <code>@</code> key, in the message tab, a list of recipients will pop up for you to select.</p>
<p>  <img src="https://github.com/user-attachments/assets/fa0aa0e6-7fc8-497f-b656-e1409255b5a0" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>Save and Activate the Monitor</strong>:</p>
<ul>
<li>Click <strong>Save</strong> to activate the monitor.</li>
</ul>
</li>
<li><p>Navigate to <code>monitor section</code> to see a list of your configured monitors.</p>
<p>  <img src="https://github.com/user-attachments/assets/5b7d66fc-069a-4f23-8b94-11c2560e9893" alt="image" /></p>
</li>
</ul>
<h3 id="heading-7-verify-the-self-healing-process"><strong>7. Verify the Self-Healing Process</strong></h3>
<ol>
<li><p><strong>Populate the</strong> <code>/demo</code> Directory:</p>
<ul>
<li><p>Open a separate session to the server.</p>
</li>
<li><p>Copy files to <code>/demo</code> directory until it reaches 95% capacity to simulate a full disk:</p>
<pre><code class="lang-bash">  dd <span class="hljs-keyword">if</span>=/dev/zero of=/demo/testfile bs=1M count=1900
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Monitor Disk Usage</strong>: (open a new session to the server)</p>
<ul>
<li><p>Run a continuous loop on your server to monitor the /demo directory:</p>
<pre><code class="lang-bash">  <span class="hljs-keyword">while</span> <span class="hljs-literal">true</span>; <span class="hljs-keyword">do</span> date &amp;&amp; ls -l &amp;&amp; <span class="hljs-built_in">pwd</span> &amp;&amp; du -ms; sleep 2; <span class="hljs-keyword">done</span>
</code></pre>
<ul>
<li><p>This command shows me the real time date, list of files, size of files and current working directory of <code>/demo</code> partition.</p>
<p>  <img src="https://github.com/user-attachments/assets/0a1ecfd5-8e53-44aa-b48d-2a54da009489" alt="image" /></p>
</li>
</ul>
</li>
<li><p>Ensure that the disk usage reaches 90% and triggers the Datadog monitor.</p>
</li>
</ul>
</li>
<li><p><strong>Check Webhook Execution</strong>:</p>
<ul>
<li><p>Verify that the webhook is called and the purge script executes as expected.</p>
<p>  <img src="https://github.com/user-attachments/assets/eba3fa3f-e11a-4dcf-b373-38207e9e908c" alt="image" /></p>
</li>
<li><p>An email will be automatically sent about the filled-up disk, and the <code>/demo</code> partition will be cleaned up.</p>
<p>  <img src="https://github.com/user-attachments/assets/a324020f-d595-4aa7-9b36-83dfc0cbb061" alt="Screenshot 2024-08-26 194702" /></p>
<p>  You will notice that the time that the email was triggered and the time the disk was full, are the same. Within seconds, the script has been executed and any upcoming disruption would have been averted.</p>
</li>
<li><p>Check the <code>/demo</code> directory to ensure that files are deleted when the threshold is crossed.</p>
<p>  <img src="https://github.com/user-attachments/assets/2003c5ff-7a68-4e8f-8fb2-63b82a563ebf" alt="Screenshot 2024-08-26 194210" /></p>
</li>
<li><p>Another email will be received to inform that the alert has been treated and closed.</p>
<p>  <img src="https://github.com/user-attachments/assets/ff522e29-79e2-4f29-97dd-a823dc63f501" alt="Screenshot 2024-08-26 194746" /></p>
</li>
</ul>
</li>
</ol>
<p>By following these detailed steps, you'll establish a realistic self-healing system. While the script provided focuses on clearing logs, it can be adapted to perform other actions, such as restarting a service, scaling an instance, or any other task. With Datadog monitoring disk usage and triggering a Node.js webhook, the system will automatically execute the necessary script, ensuring responsive and efficient management of your infrastructure. Please feel free to leave a like, comment, or ask a question if you need clarity on any of the steps. Happy Learning!</p>
]]></content:encoded></item><item><title><![CDATA[Building a Cost-Effective Kubernetes Environment with secure CI/CD Pipelines: A Comprehensive Guide]]></title><description><![CDATA[If you want to optimize costs in setting up and managing Kubernetes in a cloud environment with integrated CI/CD workflows, this guide provides practical strategies to help you achieve that.
It offers a detailed approach to installing and configuring...]]></description><link>https://devblog.seunb.com/building-a-cost-effective-kubernetes-environment-with-secure-cicd-pipelines-a-comprehensive-guide</link><guid isPermaLink="true">https://devblog.seunb.com/building-a-cost-effective-kubernetes-environment-with-secure-cicd-pipelines-a-comprehensive-guide</guid><category><![CDATA[ArgoCD]]></category><category><![CDATA[CircleCI]]></category><category><![CDATA[minikube]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Chocolatey]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Seun B]]></dc:creator><pubDate>Wed, 21 Aug 2024 02:48:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724616972213/2d097bae-c6aa-4f45-8150-da2e875481ab.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724607112524/5f12fb0b-1a3a-42c7-9390-d2946663fff8.png" alt class="image--center mx-auto" /></p>
<p>If you want to optimize costs in setting up and managing Kubernetes in a cloud environment with integrated CI/CD workflows, this guide provides practical strategies to help you achieve that.</p>
<p>It offers a detailed approach to installing and configuring essential tools for setting up Kubernetes and integrating it with CI/CD on a Windows/Desktop environment. You'll find step-by-step instructions for setting up Chocolatey, Docker, Git, Minikube, kubectl, CircleCI, and ArgoCD.<br />By following these steps, you’ll establish a robust development workflow that leverages these tools effectively while minimizing cloud costs</p>
<ol>
<li><p><strong>Prerequisites: Create accounts on the following websites if you don’t already have them:</strong></p>
<ul>
<li><p>GitHub or GitLab</p>
</li>
<li><p>Docker Hub</p>
</li>
<li><p>CircleCI</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-install-chocolatey-for-windows"><strong>Install Chocolatey for Windows</strong></h2>
<p>    Chocolatey is a package manager for Windows, designed to make the installation, upgrading, and management of software easier on the Windows platform. It's similar to package managers on other operating systems, such as <code>apt</code> on Debian-based systems or <code>yum</code> on Red Hat-based systems.</p>
<ol>
<li><p>Search for and run the PowerShell application as an Administrator.</p>
</li>
<li><p>Run the command below in the PowerShell terminal:</p>
<pre><code class="lang-powershell"> <span class="hljs-built_in">Get-ExecutionPolicy</span>
</code></pre>
<p> If it returns <code>Restricted</code>, then run:</p>
<pre><code class="lang-powershell"> <span class="hljs-built_in">Set-ExecutionPolicy</span> AllSigned
</code></pre>
<p> or</p>
<pre><code class="lang-powershell"> <span class="hljs-built_in">Set-ExecutionPolicy</span> Bypass <span class="hljs-literal">-Scope</span> <span class="hljs-keyword">Process</span>
</code></pre>
</li>
<li><p>Run the following command to install Chocolatey:</p>
<pre><code class="lang-powershell"> <span class="hljs-built_in">Set-ExecutionPolicy</span> Bypass <span class="hljs-literal">-Scope</span> <span class="hljs-keyword">Process</span> <span class="hljs-literal">-Force</span>; [<span class="hljs-type">System.Net.ServicePointManager</span>]::SecurityProtocol = [<span class="hljs-type">System.Net.ServicePointManager</span>]::SecurityProtocol <span class="hljs-operator">-bor</span> <span class="hljs-number">3072</span>; <span class="hljs-built_in">iex</span> ((<span class="hljs-built_in">New-Object</span> System.Net.WebClient).DownloadString(<span class="hljs-string">'https://community.chocolatey.org/install.ps1'</span>))
</code></pre>
<p> If you don't see any errors, you are ready to use Chocolatey! You can also visit the <a target="_blank" href="https://chocolatey.org/install">Chocolatey website</a> for an extensive guide.</p>
</li>
</ol>
<h4 id="heading-install-docker-desktop"><strong>Install Docker Desktop</strong></h4>
<ol>
<li>Follow the instructions at <a target="_blank" href="https://docs.docker.com/desktop/install/windows-install/">Docker's official documentation</a>.</li>
</ol>
<h4 id="heading-install-git"><strong>Install Git</strong></h4>
<ol>
<li>Download and install Git from <a target="_blank" href="https://git-scm.com/download/win">Git SCM</a>.</li>
</ol>
<h4 id="heading-follow-the-instructions-at-kubernetes-official-documentationhttpskubernetesiodocstaskstoolsinstall-kubectl-windows">Follow the instructions at <a target="_blank" href="https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/">Kubernetes official documentation</a>.</h4>
<p>    To install kubectl using Chocolatey:</p>
<pre><code class="lang-powershell">    choco install kubernetes<span class="hljs-literal">-cli</span>
</code></pre>
<p>    Check to ensure the version installed is up-to-date:</p>
<pre><code class="lang-bash">    kubectl version --client
</code></pre>
<h3 id="heading-minikube-for-windows"><strong>Minikube for Windows</strong></h3>
<p>    Minikube is local Kubernetes, focusing on making it easy to learn and develop for Kubernetes.</p>
<p>    All you need is Docker (or similarly compatible) container or a Virtual Machine environment, and Kubernetes is a single command away: minikube start</p>
<p>    You may visit <a target="_blank" href="https://minikube.sigs.k8s.io/docs/start/">Minikube's start guide</a> for setup.</p>
<p>    Requirements:</p>
<ul>
<li><p>2 CPUs or more</p>
</li>
<li><p>2-4GB of free memory</p>
</li>
<li><p>20GB of free disk space</p>
</li>
<li><p>Internet connection</p>
</li>
<li><p>Virtual machine manager (e.g., Docker Desktop, QEMU, Hyperkit, Hyper-V, Podman, VirtualBox, VMware Fusion/Workstation)</p>
</li>
</ul>
<p>    Install minikube with chocolatey and start your cluster:</p>
<pre><code class="lang-powershell">    choco install minikube
    minikube <span class="hljs-built_in">start</span>
</code></pre>
<p>    If that returns an error related to the virtual environment, try:</p>
<pre><code class="lang-powershell">    docker context <span class="hljs-built_in">ls</span>
    docker context use desktop<span class="hljs-literal">-linux</span>
    minikube <span class="hljs-built_in">start</span> -<span class="hljs-literal">-driver</span>=docker -<span class="hljs-literal">-docker</span><span class="hljs-literal">-env</span>=<span class="hljs-string">"desktop-linux"</span>
    OR
    minikube <span class="hljs-built_in">start</span> -<span class="hljs-literal">-driver</span>=hyperv -<span class="hljs-literal">-docker</span><span class="hljs-literal">-env</span>=<span class="hljs-string">"desktop-linux"</span>
</code></pre>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724254711102/6dfa1a82-4f2f-4786-8258-a58c235631e9.png" alt class="image--center mx-auto" /></p>
<p>    Additional Minikube commands:</p>
<pre><code class="lang-bash">    minikube version <span class="hljs-comment"># Display minikube version</span>
    minikube pause <span class="hljs-comment"># Tthis will not free up resources or stop the cluster, it will only make the service and cluster unavailable or unreachable</span>
    minikube unpause <span class="hljs-comment"># Resume cluster services</span>
    minikube stop <span class="hljs-comment"># Shuts down the virtual machine</span>
    minikube delete <span class="hljs-comment"># Destroys and clean up the VM data from disk.</span>
</code></pre>
<p>    For more information, visit <a target="_blank" href="https://minikube.sigs.k8s.io/docs/start/">Minikube's documentation</a> where you can find basic sample deployments you can try your hands on.</p>
<h4 id="heading-open-the-github-url-hotel-bookinghttpsgithubcombalogsunhotel-bookinggit-and-fork-the-repository"><strong>Open the GitHub URL</strong> <a target="_blank" href="https://github.com/balogsun/hotel-booking.git"><strong>Hotel-Booking</strong></a> <strong>and fork the repository.</strong></h4>
<ul>
<li><p>Follow the instructions to complete cloning the repository to your own github account so that you can work with the copy you have created.</p>
<p>  <img src="https://github.com/user-attachments/assets/6b80385a-038c-4f70-9ce8-f726db047693" alt="Screenshot 2024-08-19 205107" /></p>
</li>
</ul>
<h2 id="heading-set-up-circleci"><strong>Set Up CircleCI</strong></h2>
<p>    To set up and configure CircleCI for continuous integration, follow these detailed steps:</p>
<h3 id="heading-1-sign-up-and-connect-your-repository"><strong>1. Sign Up and Connect Your Repository</strong></h3>
<ul>
<li><p>Go to the <a target="_blank" href="https://circleci.com">CircleCI website</a> and sign up for a free account using GitHub or Bitbucket.</p>
</li>
<li><p>Connect an organization</p>
</li>
<li><p>Give any name of your choice as an organization</p>
</li>
<li><p>In the CircleCI dashboard, select <strong>Projects</strong> from the sidebar.</p>
</li>
<li><p>Click <strong>Create Project</strong> and choose the repository you want to connect.</p>
</li>
<li><p>What would you like to do, select <code>Build, test, and deploy a software application</code></p>
<p>  <img src="https://github.com/user-attachments/assets/79054276-b0f1-4009-9b84-27580dc1bc39" alt="Screenshot 2024-08-18 183452" /></p>
</li>
<li><p>Give your project a name.</p>
</li>
<li><p>Next, setup pipeline</p>
</li>
<li><p>Name your pipeline</p>
<p>  <img src="https://github.com/user-attachments/assets/5b6122c7-d1f1-4997-9c8c-ee935bfd95ae" alt="Screenshot 2024-08-18 184640" /></p>
</li>
<li><p>Choose a repo, select either github, gitlab or gitbucket as repo source.</p>
</li>
<li><p>Authorize CircleCI to access your GitHub or Bitbucket account.</p>
</li>
</ul>
<h3 id="heading-circlebot-will-prepare-a-custom-starter-config-file-to-build-and-test-your-code"><strong>CircleBot, will prepare a custom starter config file to build and test your code.</strong></h3>
<p>    <strong>CircleCI Configuration</strong></p>
<ul>
<li>A <code>.circleci/config.yml</code> file will be created automatically if it doesnt already exist. Review it and click <code>submit and run</code>. You may not want to run the one that is suggested for you, you may simply select to run a <code>simlpe hello world</code> option, to proceed, then go to your github repo and change it to a working config below that will build and store your codes as images in your docker hub container repository.</li>
</ul>
<h3 id="heading-configure-project-settings"><strong>Configure Project Settings</strong></h3>
<ul>
<li><p>By default. a trigger is already created for you, you can check if it exists or you create one.</p>
<p>  <img src="https://github.com/user-attachments/assets/57056a0f-0d2d-439b-a083-7a8507716ecf" alt="image" /></p>
<p>  <img src="https://github.com/user-attachments/assets/360f3943-f4fb-445a-977b-4357c1eabd22" alt="image" /></p>
</li>
</ul>
<h3 id="heading-environment-variables"><strong>Environment Variables</strong></h3>
<ul>
<li><p>To prevent authentication errors to your docker hub environment, you need to set it in your environmental variables.</p>
</li>
<li><p>In the CircleCI dashboard, go to <strong>Project Settings</strong> &gt; <strong>Environment Variables</strong>.</p>
</li>
<li><p>Add any necessary environment variables (e.g., <code>DOCKER_USER</code>, <code>DOCKER_PASS</code> for DockerHub authentication).</p>
</li>
<li><p>Put in you credentials for your dockerhub account user here.</p>
<p>  <img src="https://github.com/user-attachments/assets/39b5e438-4c02-4454-9a46-7404d7d0eb92" alt="image" /></p>
</li>
</ul>
<h3 id="heading-i-have-setup-below-a-config-file-that-will-securely-integrate-the-hotel-booking-application-for-circleci"><strong>I have setup below a Config File that will securely integrate the hotel booking application for CircleCI</strong></h3>
<p>    <strong>Note</strong>, I have deliberately instructed the security tools to bypass any vulnerability just for demo purposes only. The pipeline will fail with an <code>exit code</code> if there are any vulnerabilities found in the code or docker images built. For production purpose, remove the string <code>|| true</code> in the config file.</p>
<pre><code class="lang-yaml">    <span class="hljs-attr">version:</span> <span class="hljs-number">2.1</span>

    <span class="hljs-attr">executors:</span>
      <span class="hljs-attr">default:</span>
        <span class="hljs-attr">docker:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">image:</span> <span class="hljs-string">cimg/node:22.6.0</span>
        <span class="hljs-attr">working_directory:</span> <span class="hljs-string">~/project</span>

    <span class="hljs-attr">jobs:</span>
      <span class="hljs-attr">code_security_scan:</span>
        <span class="hljs-attr">executor:</span> <span class="hljs-string">default</span>
        <span class="hljs-attr">steps:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">checkout</span>

          <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span>
              <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span>

          <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span>
              <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">npm</span> <span class="hljs-string">audit</span> <span class="hljs-string">(ignore</span> <span class="hljs-string">failures)</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">npm</span> <span class="hljs-string">audit</span> <span class="hljs-string">--audit-level=high</span> <span class="hljs-string">||</span> <span class="hljs-literal">true</span>

      <span class="hljs-attr">build_and_scan:</span>
        <span class="hljs-attr">executor:</span> <span class="hljs-string">default</span>
        <span class="hljs-attr">steps:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">checkout</span>

          <span class="hljs-bullet">-</span> <span class="hljs-attr">setup_remote_docker:</span>
              <span class="hljs-attr">version:</span> <span class="hljs-string">default</span>  <span class="hljs-comment"># Ensure Docker is available</span>

          <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span>
              <span class="hljs-attr">name:</span> <span class="hljs-string">Docker</span> <span class="hljs-string">login</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">|
                echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span>
              <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Image</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">docker</span> <span class="hljs-string">build</span> <span class="hljs-string">-t</span> <span class="hljs-string">&lt;githubuser&gt;/hotel:v0</span> <span class="hljs-string">.</span>

          <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span>
              <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Trivy</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">|
                curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /tmp/trivy v0.54.1
                sudo ln -s /tmp/trivy/trivy /usr/local/bin/trivy
</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span>
              <span class="hljs-attr">name:</span> <span class="hljs-string">Scan</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Image</span> <span class="hljs-string">for</span> <span class="hljs-string">Vulnerabilities</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">|
                trivy image --severity HIGH,CRITICAL &lt;githubuser&gt;/hotel:v0 || true
</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span>
              <span class="hljs-attr">name:</span> <span class="hljs-string">Push</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Image</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">docker</span> <span class="hljs-string">push</span> <span class="hljs-string">&lt;githubuser&gt;/hotel:v0</span>

          <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span>
              <span class="hljs-attr">name:</span> <span class="hljs-string">Remove</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Image</span>
              <span class="hljs-attr">command:</span> <span class="hljs-string">docker</span> <span class="hljs-string">rmi</span> <span class="hljs-string">&lt;githubuser&gt;/hotel:v0</span>

    <span class="hljs-attr">workflows:</span>
      <span class="hljs-attr">version:</span> <span class="hljs-number">2</span>
      <span class="hljs-attr">build_and_deploy:</span>
        <span class="hljs-attr">jobs:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">code_security_scan</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">build_and_scan:</span>
              <span class="hljs-attr">requires:</span>
                <span class="hljs-bullet">-</span> <span class="hljs-string">code_security_scan</span>
</code></pre>
<h3 id="heading-3-commit-and-push-changes"><strong>3. Commit and Push Changes</strong></h3>
<ul>
<li>Commit the <code>.circleci/config.yml</code> file to your repository: This step is taken when you save the config file.</li>
</ul>
<h3 id="heading-5-trigger-a-build"><strong>5. Trigger a Build</strong></h3>
<ul>
<li><p>Push a commit to your github repository to trigger the first build. You can make any small modification to the <code>config.yml</code> file and commit it to initiate a trigger. This step will be mentioned again when we deploy argoCD.</p>
</li>
<li><p>Monitor the build process in the CircleCI dashboard under the <code>Pipelines</code> section.</p>
</li>
</ul>
<h3 id="heading-6-monitor-and-manage"><strong>6. Monitor and Manage</strong></h3>
<ul>
<li><p>Use the CircleCI <code>dashboard</code> --&gt; Click on <code>Pipelines</code> to view build logs, test results, and deployment status.</p>
</li>
<li><p>Failed builds are automatically sent to your email used to register a CircleCI account, sometime in junk/spam folder, you may add it to safe sender list.</p>
<p>  <img src="https://github.com/user-attachments/assets/9450570e-3290-4fc5-b829-0c2c21a129af" alt="image" /></p>
<p>  <img src="https://github.com/user-attachments/assets/a706036e-d8fe-4120-ad3a-07d2d520c4c5" alt="image" /></p>
</li>
</ul>
<p>    By following these steps, you can set up CircleCI to automate your project's build and test processes, integrating seamlessly with your existing GitHub or Bitbucket repositories.</p>
<h2 id="heading-lets-now-install-argocd"><strong>Lets now Install ArgoCD</strong></h2>
<ol>
<li><p>Create the namespace and install ArgoCD:</p>
<pre><code class="lang-bash"> kubectl create namespace argocd
 kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
</code></pre>
<pre><code class="lang-bash"> kubectl -n argocd get all
 kubectl get svc -n argocd
</code></pre>
</li>
<li><p>Change ArgoCD server service type to NodePort:</p>
<ul>
<li>Agrocd-server service is using “ClusterIP”. We can change it to NodePort” to access the agrocd UI from your local browser.</li>
</ul>
</li>
</ol>
<pre><code class="lang-bash">        kubectl edit svc argocd-server -n argocd
        OR
        kubectl edit svc argocd-server -n argocd -o yaml
</code></pre>
<p>        A notepad will be automatically opened, scroll down and change from <code>ClusterIP</code> to <code>NodePort</code>. Now <code>service</code> will be changed to “NodePort”</p>
<p>        <img src="https://github.com/user-attachments/assets/a7b8655d-00a2-4983-a69b-8d8b026cd72f" alt="Screenshot 2024-08-18 172507" /></p>
<ol start="3">
<li><p>Note the Minikube Control Plane IP Address and ArgoCD service port that will be used to access the argoCD URL:</p>
<pre><code class="lang-bash"> kubectl get node -o wide
 kubectl get svc -n argocd
</code></pre>
<p> <img src="https://github.com/user-attachments/assets/1b16b491-f457-4a7a-8026-4f2e98a74700" alt="image" /></p>
<p> <img src="https://github.com/user-attachments/assets/9857bb18-067c-44b2-a007-81761fe031a4" alt="Screenshot 2024-08-18 173906" /></p>
</li>
<li><p>Download and install Argo CD CLI:</p>
<ul>
<li><p>Visit <a target="_blank" href="https://github.com/argoproj/argo-cd/releases/tag/v2.12.1">ArgoCD releases</a> for the latest version. Explore the GitHub repo for newer release if necessary.</p>
</li>
<li><p>Run ArgoCD CLI commands from the Windows command prompt, Open windows CMD as administrator, change directory to location where you downloaded the argocd exe file. Do not double click on the exe file and try to run directly from windows, it may be flagged.</p>
<pre><code class="lang-bash">  argocd login <span class="hljs-variable">$ARGOCD_SERVER</span> --username admin --password <span class="hljs-variable">$ARGO_PWD</span> --&lt;insecure/secure&gt;

  <span class="hljs-comment">#Sample command below:</span>
  argocd-windows-amd64.exe login &lt;MinikubeIpAddress&gt;:ArgoCDServicePortNo&gt; --username admin --password xxxxxx –-insecure
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/ebf6741b-a4f0-4bad-84ba-4217fd3becbe" alt="image" /></p>
</li>
</ul>
</li>
<li><p>Access ArgoCD UI:</p>
<p> Visit <a target="_blank" href="http://ControlPlaneNodeIP:ArgocdServicePort"><code>http://ControlPlaneNodeIP:ArgocdServicePort</code></a>.</p>
</li>
<li><p>Retrieve the initial admin password: After reaching the UI for the first time, you can login with username: admin and the random password generated during the installation. You can find the password by running:</p>
<pre><code class="lang-bash"> kubectl get secret -n argocd
 kubectl describe secret argocd-initial-admin-secret -n argocd
 kubectl get secret -n argocd argocd-initial-admin-secret -o yaml
</code></pre>
<p> <img src="https://github.com/user-attachments/assets/cdbc322e-178b-422f-b352-9950086e939d" alt="image" /></p>
</li>
</ol>
<p>    The password is still encrypted so you have to decrypt it.</p>
<p>    Windows may not support native base64 decoding, you can use an online website at <a target="_blank" href="https://www.base64decode.org/">https://www.base64decode.org/</a>, insert the values and decode it.</p>
<p>    <img src="https://github.com/user-attachments/assets/36f215d0-0b50-4201-9f3c-b748d83c2e48" alt="image" /></p>
<p>    <img src="https://github.com/user-attachments/assets/83b5d485-ace9-434a-a51d-629608ea898b" alt="image" /></p>
<ul>
<li><p>We can use this password to login. After login it is recommended to change the password.</p>
</li>
<li><p>Update password in the GUI, User Info Section --&gt; update password --&gt; Save</p>
</li>
</ul>
<p>    <img src="https://github.com/user-attachments/assets/f241b221-97f4-4e20-a7f9-f7da69acac4b" alt="image" /></p>
<ol start="7">
<li><p>You should delete the initial secret afterwards:</p>
<pre><code class="lang-bash"> kubectl get secret -n argocd
 kubectl -n argocd delete secret argocd-initial-admin-secret
</code></pre>
</li>
</ol>
<ul>
<li>In the ArgoCD web interface, click on <strong>Settings</strong> -&gt; <strong>Repositories</strong>.</li>
</ul>
<p>    <img src="https://github.com/user-attachments/assets/0efd2753-711f-4b22-8a1f-7b7ffe178e73" alt="image" /></p>
<ul>
<li><p>On the next page, click on <strong>Connect Repo</strong></p>
</li>
<li><p>Fill out as below. Scroll up and click on <strong>Connect</strong>.</p>
</li>
</ul>
<p>    <img src="https://github.com/user-attachments/assets/de12d52d-e1ca-4f78-a408-8c348247ffcf" alt="image" /></p>
<h3 id="heading-now-we-have-connected-our-github-repository-with-argocd-next-is-to-create-an-application"><strong>Now we have connected our GitHub repository with ArgoCD. Next is to create an application.</strong></h3>
<ul>
<li>Click on the <strong>Applications</strong> page and click on <strong>Create New App</strong>.</li>
</ul>
<p>    <img src="https://github.com/user-attachments/assets/45052278-ab51-4bcc-bc22-2e3e8f3c750a" alt="image" /></p>
<ul>
<li>Fill in the details as below.</li>
</ul>
<p>    <img src="https://github.com/user-attachments/assets/5d17d85e-cc29-47cc-b07c-85816e52475b" alt="image" /></p>
<ul>
<li><p>Scroll down the page and fill in the <code>source</code> and <code>destination</code> details. The deployment YAML for our case repo is inside the <code>K8S</code> path; we need to put that as our path.</p>
</li>
<li><p>Select the cluster URL and namespace. Now click on <strong>Create</strong>. It will create the app.</p>
<p>  <img src="https://github.com/user-attachments/assets/f3f85dec-a678-412e-8bc2-386a3ec11b59" alt="image" /></p>
<p>  <img src="https://github.com/user-attachments/assets/6745db79-124c-4011-a486-da3162c3f9c2" alt="image" /></p>
</li>
<li><p>Upon completion of the creation, argoCD will attempt to automatically deploy the hotel app using the <code>K8S</code> path that we have defined, this is where the <code>deployment.yml file</code> was placed. Upon successful deployment, We will find the hotel app deployed in the minikube cluster.</p>
<pre><code class="lang-bash">  kubectl get all
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/26231819-5434-4f7f-84f8-8a9e756da34d" alt="Screenshot 2024-08-18 202348" /></p>
</li>
<li><p>We can access the hotel app using the <code>minikube controlplane NodeIP</code> and <code>hotel service port no</code>.</p>
</li>
</ul>
<pre><code class="lang-bash">    kubectl get nodes -o wide
</code></pre>
<p>    <img src="https://github.com/user-attachments/assets/59374775-5e40-45aa-ac80-73476b370283" alt="Screenshot 2024-08-18 172735" /></p>
<p>    From the checks above, URL will be <a target="_blank" href="http://172.27.217.12:30537"><code>http://172.27.217.12:30537</code></a></p>
<ul>
<li><p>Now we can make a change/update to the booking app by modifying a content of the source codes, here i have modified some details in the <code>src\routes\home\home.jsx</code> path. Once the file is saved and committed, CircleCI previously configured will automatically detect this change and run the pipeline in <code>.CircleCI/config.yml</code>, to scan and build a new image, then push it to Docker Hub repository, ready for deployment by argoCD.</p>
<p>  <img src="https://github.com/user-attachments/assets/01cbede9-0d4f-48b0-a83b-a544502e783a" alt="image" /></p>
</li>
<li><p>Update that image details in your <code>K8S/deployment.yml</code> file in your repo and click on <strong>Sync</strong> in the argoCD app. This means that if CircleCI builds an image with a tag of v2, then you have to update the image tag in <code>K8S/deployment.yml</code> to v2 also.</p>
</li>
</ul>
<p>    The hotel-deployment in you cluster will be automatically updated with the new modification you have made.</p>
<p>    <img src="https://github.com/user-attachments/assets/7d20c9ca-e477-4612-8552-cfb07451cf32" alt="image" /></p>
<p>    <img src="https://github.com/user-attachments/assets/1a9c3aad-c343-4e4d-9e35-beed5a9a3eca" alt="Screenshot 2024-08-18 233712" /></p>
<p>    <img src="https://github.com/user-attachments/assets/2462aa94-285a-43f2-b75a-b165647dfead" alt="image" /></p>
<ul>
<li><p>When you click on <strong>Sync</strong> with argoCD, you have some options tick boxes to select from. If using Argo CD for the first time in a development environment, here are some basic options you might consider selecting:</p>
</li>
<li><p><img src="https://github.com/user-attachments/assets/64a9f530-a153-4b8c-b160-7fbfc5b55dfc" alt="image" /></p>
</li>
</ul>
<p>    <img src="https://github.com/user-attachments/assets/928a49bd-ac0f-4f51-82a6-d057d7bac4e5" alt="image" /></p>
<h3 id="heading-options"><strong>Options</strong></h3>
<ul>
<li><p><strong>Revision</strong>: The revision is set to <code>HEAD</code>, which means the latest commit in the default branch will be used.</p>
</li>
<li><p><strong>DRY RUN</strong>: This is a safe option to start with as it allows you to simulate the synchronization process without making any actual changes. It helps you verify what changes would be applied.</p>
</li>
</ul>
<h3 id="heading-sync-options"><strong>Sync Options</strong></h3>
<ul>
<li><p><strong>AUTO-CREATE NAMESPACE</strong>: Useful if you want Argo CD to automatically create the namespace for your application if it doesn’t exist. This can simplify setup in a development environment.</p>
</li>
<li><p><strong>APPLY OUT OF SYNC ONLY</strong>: This option ensures that only resources that are out of sync with the Git repository are updated, which can be useful for incremental updates.</p>
</li>
</ul>
<h3 id="heading-additional-considerations"><strong>Additional Considerations</strong></h3>
<ul>
<li><p><strong>PRUNE</strong>: You might want to use this cautiously. In a development environment, it can be useful to remove resources not defined in your Git repository, but ensure you understand its impact first.</p>
</li>
<li><p><strong>RETRY</strong>: Consider enabling this if you want Argo CD to automatically retry synchronization in case of failure, which can be helpful during development when changes are frequent.</p>
</li>
</ul>
<p>    These options provide a balance between safety and functionality, allowing you to manage your applications effectively while minimizing risks.</p>
<h3 id="heading-prune-propagation-policy"><strong>Prune Propagation Policy</strong></h3>
<ul>
<li><strong>FOREGROUND</strong>: Deletes resources in the foreground, blocking until the resource is fully deleted.</li>
</ul>
<h3 id="heading-additional-options"><strong>Additional Options</strong></h3>
<ul>
<li><strong>REPLACE</strong>: Replaces resources instead of updating them, which may lead to downtime.</li>
</ul>
<p>    This configuration is used to manage how Argo CD synchronizes application manifests from a Git repository to a Kubernetes cluster. Each option provides control over how resources are applied and managed during the sync process.</p>
<h3 id="heading-in-conclusion"><strong>In Conclusion</strong></h3>
<p>    By following this guide, you’ll have set up a budget-friendly CI/CD system running kubernetes on your Windows/Desktop using tools like Chocolatey, Docker, Git, Minikube, kubectl, CircleCI, and ArgoCD. This setup makes your development process smoother and cuts down on cloud costs.</p>
<p>    You’ll discover how to set up and use each tool, connect them together, and automate your development tasks. With Minikube, you can run Kubernetes locally, and with CircleCI+ArgoCD, you can integrate/deploy and manage your apps.</p>
<p>    Using these tools will help you manage your code, build projects, and deploy apps more easily and effectively, making your development work more reliable and efficient.</p>
]]></content:encoded></item><item><title><![CDATA[Securing your Cloud Infrastructure: A comprehensive guide to hardening, scaling, automating and monitoring your servers]]></title><description><![CDATA[Introduction:
In today's fast-paced tech environment, launching a new product often requires setting up a secure and scalable infrastructure, quickly and efficiently. As a Cloud platform or DevOps engineer, your role is critical in ensuring that thes...]]></description><link>https://devblog.seunb.com/securing-your-cloud-infrastructure-a-comprehensive-guide-to-hardening-scaling-automating-and-monitoring-your-servers</link><guid isPermaLink="true">https://devblog.seunb.com/securing-your-cloud-infrastructure-a-comprehensive-guide-to-hardening-scaling-automating-and-monitoring-your-servers</guid><category><![CDATA[Linux]]></category><category><![CDATA[#LinuxPermissions #UserPermissions #FilePermissions #DirectoryPermissions #LinuxSecurity #AccessControl #Setuid #Setgid #StickyBit #LinuxUserAccounts #OwnershipAndPermissions #LinuxFileSystem #CommandLine #LinuxAdministration #SystemSecurity]]></category><category><![CDATA[ansible-playbook]]></category><category><![CDATA[ansible]]></category><category><![CDATA[elk]]></category><category><![CDATA[monitoring]]></category><category><![CDATA[linux-hardening]]></category><category><![CDATA[apache]]></category><category><![CDATA[fail2ban]]></category><category><![CDATA[postfix]]></category><dc:creator><![CDATA[Seun B]]></dc:creator><pubDate>Thu, 15 Aug 2024 03:53:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/5fNmWej4tAA/upload/79216eeed65caa44bfc4d732e6593e3d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction"><strong>Introduction:</strong></h2>
<p>In today's fast-paced tech environment, launching a new product often requires setting up a secure and scalable infrastructure, quickly and efficiently. As a Cloud platform or DevOps engineer, your role is critical in ensuring that these servers are not only operational but also secure against potential threats. This guide takes you through a real-world scenario of securing new set of web servers from scratch, covering everything from initial server hardening to advanced automation and monitoring techniques. By the end, you'll gain knowledge of how to have a robust, repeatable process for securing and managing Linux web servers, ready to be scaled across your infrastructure.</p>
<p>Let's walk through creating a repeatable process that can be applied to multiple servers, ensuring they are all configured securely and consistently. I will be hardening the system, setting up file integrity monitoring, system audit, central logging solution and finally automating the process with ansible.</p>
<p>Below is a bash script for basic system hardening of an Ubuntu server. It can definitely be applied to some other linux flavous as needed. The script covers some security measures to ensure the server is suitably protected. After the script, I'll explain each stage in detail.</p>
<h3 id="heading-bash-script-nano-systemhardeningsh">Bash Script: <code>nano system_hardening.sh</code></h3>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Ensure the script is run as root</span>
<span class="hljs-keyword">if</span> [ <span class="hljs-string">"<span class="hljs-subst">$(id -u)</span>"</span> -ne 0 ]; <span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"This script must be run as root. Exiting."</span>
    <span class="hljs-built_in">exit</span> 1
<span class="hljs-keyword">fi</span>

<span class="hljs-comment"># Update and upgrade the system</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Updating and upgrading the system..."</span>
apt update &amp;&amp; apt upgrade -y

<span class="hljs-comment"># 1. Disable root login via SSH</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Disabling root login via SSH..."</span>
sed -i <span class="hljs-string">'s/^PermitRootLogin.*/PermitRootLogin no/'</span> /etc/ssh/sshd_config


<span class="hljs-comment"># 2. Enable logging of sudo commands</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Enabling logging of sudo commands..."</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Defaults logfile=/var/log/sudo.log"</span> &gt;&gt; /etc/sudoers

<span class="hljs-comment"># 3. Install and configure UFW (Uncomplicated Firewall)</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Installing and configuring UFW..."</span>
apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw <span class="hljs-built_in">enable</span>

<span class="hljs-comment"># 4. Disable unused filesystems</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Disabling unused filesystems..."</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"install cramfs /bin/true"</span> &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
<span class="hljs-built_in">echo</span> <span class="hljs-string">"install freevxfs /bin/true"</span> &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
<span class="hljs-built_in">echo</span> <span class="hljs-string">"install jffs2 /bin/true"</span> &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
<span class="hljs-built_in">echo</span> <span class="hljs-string">"install hfs /bin/true"</span> &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
<span class="hljs-built_in">echo</span> <span class="hljs-string">"install hfsplus /bin/true"</span> &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
<span class="hljs-built_in">echo</span> <span class="hljs-string">"install udf /bin/true"</span> &gt;&gt; /etc/modprobe.d/disable-filesystems.conf

<span class="hljs-comment"># 5. Set strong password policies</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Setting strong password policies..."</span>
apt install -y libpam-pwquality
sed -i <span class="hljs-string">'s/^# minlen.*/minlen = 12/'</span> /etc/security/pwquality.conf
sed -i <span class="hljs-string">'s/^# dcredit.*/dcredit = -1/'</span> /etc/security/pwquality.conf
sed -i <span class="hljs-string">'s/^# ucredit.*/ucredit = -1/'</span> /etc/security/pwquality.conf
sed -i <span class="hljs-string">'s/^# lcredit.*/lcredit = -1/'</span> /etc/security/pwquality.conf
sed -i <span class="hljs-string">'s/^# ocredit.*/ocredit = -1/'</span> /etc/security/pwquality.conf

<span class="hljs-comment"># 6. Disable IPv6 if not needed</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Disabling IPv6..."</span>
sed -i <span class="hljs-string">'s/^#net.ipv6.conf.all.disable_ipv6 = 1/net.ipv6.conf.all.disable_ipv6 = 1/'</span> /etc/sysctl.conf
sysctl -p

<span class="hljs-comment"># 7. Secure shared memory</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Securing shared memory..."</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0"</span> &gt;&gt; /etc/fstab

<span class="hljs-comment"># 8. Remove unnecessary packages</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Removing unnecessary packages..."</span>
apt-get autoremove -y --purge

<span class="hljs-comment"># 9. Install and configure rkhunter</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Installing and configuring rkhunter..."</span>
apt install -y rkhunter
rkhunter --update
rkhunter --propupd
rkhunter --check --sk

<span class="hljs-comment"># 10. Set up log file permissions</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Setting up log file permissions..."</span>
chmod -R go-rwx /var/<span class="hljs-built_in">log</span>/*

<span class="hljs-comment"># 11. Configure login banner</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Configuring login banner..."</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Authorized access only. All activity may be monitored and reported."</span> &gt; /etc/issue.net
sed -i <span class="hljs-string">'s/^#Banner.*/Banner \/etc\/issue.net/'</span> /etc/ssh/sshd_config

<span class="hljs-comment"># 12. Set up limits on user processes</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Setting up limits on user processes..."</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"* hard nproc 100"</span> &gt;&gt; /etc/security/limits.conf

<span class="hljs-comment"># 13. Restrict cron jobs to authorized users</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Restricting cron jobs to authorized users..."</span>
touch /etc/cron.allow
chmod 600 /etc/cron.allow

<span class="hljs-comment"># 14. Restrict access to su command</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Restricting access to su command..."</span>

<span class="hljs-comment"># Ensure required package is installed.</span>
apt install -y libpam-modules

<span class="hljs-comment"># Configure PAM to restrict access to su command.</span>
<span class="hljs-keyword">if</span> ! grep -q <span class="hljs-string">"auth required pam_wheel.so use_uid"</span> /etc/pam.d/su; <span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"auth required pam_wheel.so use_uid"</span> &gt;&gt; /etc/pam.d/su
<span class="hljs-keyword">fi</span>

<span class="hljs-comment"># Create the 'wheel' group if it does not exist</span>
<span class="hljs-keyword">if</span> ! getent group wheel &gt; /dev/null; <span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Creating 'wheel' group..."</span>
    groupadd wheel
<span class="hljs-keyword">fi</span>

<span class="hljs-comment"># Add the 'ubuntu' user to the 'wheel' group</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Adding 'ubuntu' user to 'wheel' group..."</span>
usermod -aG wheel ubuntu

<span class="hljs-built_in">echo</span> <span class="hljs-string">"su command access restricted to 'wheel' group members, including 'ubuntu' user."</span>

<span class="hljs-comment"># 15. Disable core dumps</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Disabling core dumps..."</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"* hard core 0"</span> &gt;&gt; /etc/security/limits.conf
<span class="hljs-built_in">echo</span> <span class="hljs-string">"fs.suid_dumpable = 0"</span> &gt;&gt; /etc/sysctl.conf
sysctl -p

<span class="hljs-comment"># 16. Enable ASLR (Address Space Layout Randomization)</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Enabling ASLR..."</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"kernel.randomize_va_space = 2"</span> &gt;&gt; /etc/sysctl.conf
sysctl -p

<span class="hljs-comment"># Restart SSH to apply changes</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Restarting SSH service..."</span>
systemctl restart ssh

<span class="hljs-built_in">echo</span> <span class="hljs-string">"System hardening completed."</span>
</code></pre>
<p>Make the script executable and run it.</p>
<pre><code class="lang-bash">chmod 764 system_hardening.sh
</code></pre>
<pre><code class="lang-bash">./chmod 764 system_hardening.sh
</code></pre>
<p>Snippet of the script running</p>
<p><img src="https://github.com/user-attachments/assets/0ceddca4-dd50-4845-acac-d59a352e5d4a" alt="Screenshot 2024-08-09 100220" /></p>
<h3 id="heading-summary-of-hardening-steps">Summary of Hardening Steps</h3>
<ol>
<li><p><strong>Update the server packages.</strong></p>
</li>
<li><p><strong>Disable root login via SSH</strong>: Prevents direct root login, reducing the risk of brute force attacks on the root account.</p>
</li>
<li><p><strong>Enable logging of sudo commands</strong>: Tracks all commands executed with <code>sudo</code>, enhancing accountability and auditability.</p>
</li>
<li><p><strong>Install and configure UFW (Uncomplicated Firewall)</strong>: Sets up a simple firewall to manage incoming and outgoing traffic.</p>
</li>
<li><p><strong>Disable unused filesystems</strong>: Prevents the loading of unnecessary and potentially vulnerable filesystems.</p>
</li>
<li><p><strong>Set strong password policies</strong>: Enforces strong password requirements to reduce the risk of password-based attacks. These settings enforce a minimum password length of 12 characters with at least one digit, uppercase letter, lowercase letter, and special character.</p>
</li>
<li><p><strong>Disable IPv6 if not needed</strong>: Disables IPv6 to reduce the attack surface if it's not in use.</p>
</li>
<li><p><strong>Secure shared memory</strong>: Protects shared memory by mounting it with restrictive options.</p>
</li>
<li><p><strong>Remove unnecessary packages</strong>: Reduces the attack surface by removing unused packages.</p>
</li>
<li><p><strong>Install and configure rkhunter</strong>: Checks for rootkits and other security issues on the server.</p>
</li>
<li><p><strong>Set up log file permissions</strong>: Ensures that log files are protected from unauthorized access.</p>
</li>
<li><p><strong>Configure login banner</strong>: Displays a warning message to users before login, indicating monitoring and restrictions.</p>
</li>
<li><p><strong>Set up limits on user processes</strong>: Limits the number of processes a user can run, preventing fork bomb attacks.</p>
</li>
<li><p><strong>Restrict cron jobs to authorized users</strong>: Only allows authorized users to create and edit cron jobs, reducing the risk of malicious cron tasks.</p>
</li>
<li><p><strong>Restrict access to su command</strong>: Limits access to the <code>su</code> command to authorized users, preventing unauthorized privilege escalation.</p>
</li>
<li><p><strong>Disable core dumps</strong>: Prevents the creation of core dumps, which could contain sensitive information.</p>
</li>
<li><p><strong>Enable ASLR (Address Space Layout Randomization)</strong>: Randomizes memory addresses, making it more difficult for attackers to exploit vulnerabilities.</p>
</li>
</ol>
<p>This script now focuses on securing a Linux server by implementing a set of essential hardening measures without adding new tools or services beyond those already included.</p>
<p>This script is designed to cover a wide range of basic security measures that are generally applicable to many environments. For your specific production environment, additional hardening steps might be needed depending on the specific use case.</p>
<h4 id="heading-now-lets-test-some-of-the-functionalities-that-the-script-has-implemented">Now lets test some of the functionalities that the script has implemented</h4>
<ul>
<li><p>vagrant user is not a member of wheel and was not able to perform su functions, unlike the ubuntu user.</p>
<p>  <img src="https://github.com/user-attachments/assets/3ff910f6-31bf-4076-8830-dfadd04cc8e5" alt="Screenshot 2024-08-09 100426" /></p>
</li>
<li><p>vagrant user tried to change password that did not meet up with strong password policies and that attempt failed.</p>
<p>  <img src="https://github.com/user-attachments/assets/025ef59d-faa5-4edd-8104-dd5206aa020a" alt="Screenshot 2024-08-09 100829" /></p>
</li>
<li><p>display banner is shown whenever a user logs in.</p>
</li>
<li><p>root user could no longer make a direct ssh login</p>
</li>
</ul>
<h2 id="heading-next-we-can-install-and-setup-fail2ban">Next we can install and setup <code>Fail2ban</code></h2>
<p>A security tool designed to protect servers from brute-force attacks, protecting services such as SSH, HTTP, and FTP by monitoring log files for suspicious activity and automatically banning offending IP addresses. It works by defining "jails" for specific services like SSH, HTTP, and FTP, where it monitors for failed login attempts or other malicious behavior. When a threshold of failures is reached, Fail2ban modifies firewall rules to block the IP for a set period. The tool is highly configurable, allowing custom filters and flexible ban durations, and it automatically unbans IPs after the ban period expires.</p>
<p>Below is a script that will install and setup a basic configuration that provides a strong level of security, but you can further tailor it to meet specific needs by creating custom jails and filters.</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Fail2ban installation and configuration script</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Updating package list..."</span>
sudo apt update

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Installing Fail2ban..."</span>
sudo apt install -y fail2ban

<span class="hljs-comment"># Create a local copy of the jail configuration file for custom settings if not already present</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Creating local configuration file..."</span>
<span class="hljs-keyword">if</span> [ ! -f /etc/fail2ban/jail.local ]; <span class="hljs-keyword">then</span>
    sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
<span class="hljs-keyword">fi</span>

<span class="hljs-comment"># Backup existing jail.local before modifying</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Backing up existing jail.local..."</span>
sudo cp /etc/fail2ban/jail.local /etc/fail2ban/jail.local.bak

<span class="hljs-comment"># Append new configuration settings to jail.local</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Configuring Fail2ban..."</span>
sudo bash -c <span class="hljs-string">'echo -e "[DEFAULT]\n# Whitelist your own IPs\nignoreip = 127.0.0.1/8 ::1 &lt;ipaddress&gt;/24 &lt;ipaddress&gt;/24\n\n# Ban time in seconds (e.g., 10 minutes)\nbantime = 600\n\n# Time frame for counting failures in seconds\nfindtime = 600\n\n# Max retry attempts before banning\nmaxretry = 5\n\n[sshd]\nenabled = true\nport = ssh\nlogpath = %(sshd_log)s\nmaxretry = 5" | sudo tee /etc/fail2ban/jail.local &gt; /dev/null'</span>

<span class="hljs-comment"># Restart and enable Fail2ban service</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Starting and enabling Fail2ban service..."</span>
sudo systemctl restart fail2ban
sudo systemctl <span class="hljs-built_in">enable</span> fail2ban

<span class="hljs-comment"># Display the status of the Fail2ban service</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Checking Fail2ban status..."</span>
sudo systemctl status fail2ban

<span class="hljs-comment"># Optional: Monitor Fail2ban logs</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"You can monitor Fail2ban logs with the following command:"</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"sudo tail -f /var/log/fail2ban.log"</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Fail2ban installation and configuration completed."</span>
</code></pre>
<h3 id="heading-how-to-use-the-script">How to Use the Script</h3>
<ol start="2">
<li><p><strong>Make the Script Executable:</strong> Run the following command to make the script executable:</p>
<pre><code class="lang-bash"> chmod +x install_fail2ban.sh
</code></pre>
</li>
<li><p><strong>Run the Script:</strong> Execute the script with <code>sudo</code> to install and configure Fail2ban:</p>
<pre><code class="lang-bash"> sudo ./install_fail2ban.sh
</code></pre>
</li>
</ol>
<h3 id="heading-what-this-script-does">What This Script Does</h3>
<ul>
<li><p><strong>Installs Fail2ban</strong> using the package manager.</p>
</li>
<li><p><strong>Creates a local configuration file</strong> (<code>jail.local</code>) to customize settings without affecting the default <code>jail.conf</code>.</p>
</li>
<li><p><strong>Configures Fail2ban</strong> with some basic settings:</p>
<ul>
<li><p>Whitelisting local IPs.</p>
</li>
<li><p>Setting ban time, find time, and maximum retries.</p>
</li>
<li><p>Enabling and configuring the SSH jail.</p>
</li>
</ul>
</li>
<li><p><strong>Starts and enables</strong> the Fail2ban service to run at boot.</p>
</li>
<li><p><strong>Provides the status</strong> of the Fail2ban service for verification.</p>
</li>
<li><p><strong>Offers a command</strong> to monitor Fail2ban logs for real-time information.</p>
</li>
</ul>
<h3 id="heading-other-commands-to-try">Other commands to try</h3>
<p>List Banned IPs</p>
<pre><code class="lang-bash">sudo fail2ban-client status ssh
</code></pre>
<p><img src="https://github.com/user-attachments/assets/97bf746d-0335-4a22-858a-009b7e2f91a4" alt="image" /></p>
<p>This will show the number of currently banned IPs and the list of banned IPs.</p>
<p>If you need to unban an IP address manually:</p>
<pre><code class="lang-bash">sudo fail2ban-client <span class="hljs-built_in">set</span> sshd unbanip &lt;IP_ADDRESS&gt;
</code></pre>
<ul>
<li>Replace &lt;IP_ADDRESS&gt; with the actual IP address you want to unban.</li>
</ul>
<p>This script automates the entire process of installing and configuring Fail2ban, making it easy to secure your server against brute-force attacks.</p>
<p>Now this same server has an alternate IP, i attempted to make several failed attempts to it and here are the logs showing the IP being banned, and future connections from that IP were no longer permitted.</p>
<p><img src="https://github.com/user-attachments/assets/bdcac231-8d1a-409f-a17b-1b373e8eec1f" alt="image" /></p>
<h2 id="heading-next-lets-install-and-configure-a-basic-web-server-apache">Next, Lets install and configure a basic web server <code>Apache</code></h2>
<p>To install and configure a web server on Ubuntu, you can use Apache or nginx. I have created a custom html document (a simple pizza booking website) for this purpose and here's a step-by-step guide to install and configure Apache:</p>
<h3 id="heading-bash-script-for-installing-and-configuring-apache">Bash Script for Installing and Configuring Apache</h3>
<pre><code class="lang-bash">nano apache.sh
</code></pre>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Web server installation and configuration script</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Installing Apache..."</span>
sudo apt install -y apache2

<span class="hljs-comment"># Ensure Apache is running and enabled on boot</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Starting and enabling Apache service..."</span>
sudo systemctl start apache2
sudo systemctl <span class="hljs-built_in">enable</span> apache2

<span class="hljs-comment"># Configure firewall to allow HTTP and HTTPS traffic</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Configuring firewall..."</span>
sudo ufw allow <span class="hljs-string">'Apache Full'</span>

<span class="hljs-comment"># Create a simple HTML file for the custom site</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Creating a pizza ordering web page..."</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">'&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;title&gt;Order Your Pizza&lt;/title&gt;
    &lt;style&gt;
        body {
            background-color: #f4f4f9;
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            color: #333;
            text-align: center;
        }
        header {
            background-color: #808080; /* Grey */
            color: white;
            padding: 20px;
        }
        h1 {
            margin: 0;
            font-size: 2.5em;
        }
        h2 {
            font-size: 1.5em;
            margin-top: 0.5em;
            color: #555;
        }
        h3 {
            font-size: 1.2em;
            margin-top: 1em;
            color: #333;
        }
        .container {
            max-width: 800px;
            margin: 20px auto;
            padding: 20px;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }
        .form-group {
            margin-bottom: 15px;
            text-align: left;
        }
        .form-group input {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        .toppings {
            display: flex;
            justify-content: center;
            flex-wrap: wrap;
        }
        .toppings div {
            margin: 10px;
            font-size: 1.1em;
        }
        .button {
            background-color: #4CAF50; /* Green */
            border: none;
            color: white;
            padding: 15px 25px;
            text-align: center;
            text-decoration: none;
            display: inline-block;
            font-size: 16px;
            margin: 10px;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }
        .button:hover {
            background-color: #45a049;
        }
        .button.reset {
            background-color: #e7e7e7; /* Gray */
            color: black;
        }
        .button.reset:hover {
            background-color: #d5d5d5;
        }
        img {
            max-width: 100%;
            height: auto;
            margin-top: 20px;
            border-radius: 8px;
        }
        footer {
            margin-top: 20px;
            font-size: 14px;
            color: #777;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;header&gt;
        &lt;h1&gt;Your One Stop Shop for Great Pizzas&lt;/h1&gt;
    &lt;/header&gt;
    &lt;div class="container"&gt;
        &lt;h2&gt;Kindly Make Your Order by Filling the Details Below&lt;/h2&gt;
        &lt;form&gt;
            &lt;div class="form-group"&gt;
                &lt;label for="name"&gt;Name:&lt;/label&gt;
                &lt;input type="text" id="name" placeholder="Your Name" required&gt;
            &lt;/div&gt;
            &lt;div class="form-group"&gt;
                &lt;label for="email"&gt;Email:&lt;/label&gt;
                &lt;input type="email" id="email" placeholder="Your Email" required&gt;
            &lt;/div&gt;
            &lt;div class="form-group"&gt;
                &lt;label for="phone"&gt;Phone No:&lt;/label&gt;
                &lt;input type="tel" id="phone" placeholder="Your Phone Number" required&gt;
            &lt;/div&gt;
            &lt;h3&gt;Select Pizza Toppings&lt;/h3&gt;
            &lt;div class="toppings"&gt;
                &lt;div&gt;&lt;input type="checkbox" id="chicken"&gt;&lt;label for="chicken"&gt; Chicken&lt;/label&gt;&lt;/div&gt;
                &lt;div&gt;&lt;input type="checkbox" id="pepperoni"&gt;&lt;label for="pepperoni"&gt; Pepperoni&lt;/label&gt;&lt;/div&gt;
                &lt;div&gt;&lt;input type="checkbox" id="sausage"&gt;&lt;label for="sausage"&gt; Sausage&lt;/label&gt;&lt;/div&gt;
                &lt;div&gt;&lt;input type="checkbox" id="mushrooms"&gt;&lt;label for="mushrooms"&gt; Mushrooms&lt;/label&gt;&lt;/div&gt;
            &lt;/div&gt;
            &lt;button type="submit" class="button"&gt;Submit&lt;/button&gt;
            &lt;button type="reset" class="button reset"&gt;Reset&lt;/button&gt;
        &lt;/form&gt;
    &lt;/div&gt;
    &lt;img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Pizza-3007395.jpg/1280px-Pizza-3007395.jpg" alt="Pizza"&gt;
    &lt;footer&gt;
        &lt;h4&gt;All Rights Reserved&lt;/h4&gt;
    &lt;/footer&gt;
&lt;/body&gt;
&lt;/html&gt;'</span> | sudo tee /var/www/html/index.html &gt; /dev/null

<span class="hljs-comment"># Remove the default site configuration</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Removing the default site configuration..."</span>
sudo a2dissite 000-default.conf

<span class="hljs-comment"># Create and enable custom site configuration</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Creating custom site configuration..."</span>
sudo tee /etc/apache2/sites-available/custom-site.conf &gt; /dev/null &lt;&lt;EOF
&lt;VirtualHost *:80&gt;
    DocumentRoot /var/www/html
    &lt;Directory /var/www/html&gt;
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    &lt;/Directory&gt;
    ErrorLog <span class="hljs-variable">${APACHE_LOG_DIR}</span>/error.log
    CustomLog <span class="hljs-variable">${APACHE_LOG_DIR}</span>/access.log combined
&lt;/VirtualHost&gt;
EOF

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Enabling the custom site configuration..."</span>
sudo a2ensite custom-site.conf

<span class="hljs-comment"># Restart Apache to apply any configuration changes</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Restarting Apache..."</span>
sudo systemctl restart apache2

<span class="hljs-comment"># Display Apache status</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Checking Apache status..."</span>
sudo systemctl status apache2

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Apache installation and configuration completed. You can access your web server at http://&lt;your-server-ip&gt;."</span>
</code></pre>
<p><strong>Save the Script</strong>: Save the script as <code>install_configure_</code><a target="_blank" href="http://apache.sh"><code>apache.sh</code></a>. <strong>Make it Executable</strong>:</p>
<pre><code class="lang-bash">chmod +x apache.sh
</code></pre>
<p><strong>Run the Script</strong>:</p>
<pre><code class="lang-bash">sudo ./apache.sh
</code></pre>
<p><strong>A snippet of the script when run</strong></p>
<p><img src="https://github.com/user-attachments/assets/509e8834-6c3b-473e-86d8-914d846080cc" alt="Screenshot 2024-08-09 113613" /></p>
<h3 id="heading-accessing-the-web-server">Accessing the Web Server</h3>
<p>Once the script completes, you can access the web server by navigating to <code>http://&lt;your-server-ip&gt;</code> in your web browser. You should see the simple HTML page you created.</p>
<p>Also ensure to set up SSL for Apache for secure communication between users and the application. Proper SSL/TLS configuration will encrypt data in transit, protect against man-in-the-middle attacks, and build trust with your users by validating your server’s identity.</p>
<p><img src="https://github.com/user-attachments/assets/982eba30-81a7-4f71-8a12-d3c1572ec461" alt="Screenshot 2024-08-09 113842" /></p>
<h3 id="heading-next-lets-setup-file-integrity-monitoring-with-aide-advanced-intrusion-detection-environment-to-help-you-monitor-file-integrity-effectively-and-receive-daily-reports">Next lets setup File Integrity Monitoring with AIDE (Advanced Intrusion Detection Environment), to help you monitor file integrity effectively and receive daily reports</h3>
<p>To implement File Integrity Monitoring with AIDE (Advanced Intrusion Detection Environment), follow these steps: We will also be setting up mail services using gmail.</p>
<p>One Needs to Have 2-Step Verification Enabled for Google mail Account as Less Secure Apps has been deprecated.</p>
<ol>
<li><p>Navigate to <a target="_blank" href="https://myaccount.google.com/apppasswords"><code>https://myaccount.google.com/apppasswords</code></a>.</p>
</li>
<li><p>Name and Create your app, then click the <code>Create</code> button.</p>
</li>
<li><p>A new app password will be generated for you. Copy this password.</p>
</li>
</ol>
<h3 id="heading-1-install-aide">1. <strong>Install AIDE</strong></h3>
<pre><code class="lang-bash"><span class="hljs-comment"># !/bin/bash</span>

<span class="hljs-comment"># Install AIDE</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Installing AIDE..."</span>
sudo apt-get install -y aide

<span class="hljs-comment"># Backup the existing AIDE configuration file</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Backing up AIDE configuration..."</span>
sudo cp /etc/aide/aide.conf /etc/aide/aide.conf.bkup

<span class="hljs-comment"># Add exclusions to AIDE configuration file</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Configuring AIDE exclusions..."</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"!/tmp"</span> | sudo tee -a /etc/aide/aide.conf &gt; /dev/null
<span class="hljs-built_in">echo</span> <span class="hljs-string">"!/var/spool"</span> | sudo tee -a /etc/aide/aide.conf &gt; /dev/null

<span class="hljs-comment"># Initialize AIDE database</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Initializing AIDE database. This may take a while..."</span>
sudo aide -c /etc/aide/aide.conf --init

<span class="hljs-comment"># Move the new AIDE database to the correct location</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Moving AIDE database..."</span>
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db

<span class="hljs-comment"># Run an AIDE check against the initialized database</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Running AIDE check. This may take a while..."</span>
sudo aide -c /etc/aide/aide.conf --check

<span class="hljs-comment"># Install Postfix</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Installing Postfix..."</span>
sudo apt-get install -y postfix

<span class="hljs-comment"># Configure Postfix for Gmail relay</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Configuring Postfix..."</span>
sudo sed -i <span class="hljs-string">'/^relayhost =/d'</span> /etc/postfix/main.cf
<span class="hljs-built_in">echo</span> <span class="hljs-string">"relayhost = [smtp.gmail.com]:587"</span> | sudo tee -a /etc/postfix/main.cf &gt; /dev/null
<span class="hljs-built_in">echo</span> <span class="hljs-string">"smtp_use_tls = yes"</span> | sudo tee -a /etc/postfix/main.cf &gt; /dev/null
<span class="hljs-built_in">echo</span> <span class="hljs-string">"smtp_sasl_auth_enable = yes"</span> | sudo tee -a /etc/postfix/main.cf &gt; /dev/null
<span class="hljs-built_in">echo</span> <span class="hljs-string">"smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd"</span> | sudo tee -a /etc/postfix/main.cf &gt; /dev/null
<span class="hljs-built_in">echo</span> <span class="hljs-string">"smtp_sasl_security_options = noanonymous"</span> | sudo tee -a /etc/postfix/main.cf &gt; /dev/null

<span class="hljs-comment"># Create sasl_passwd file for Postfix</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Creating SASL password file..."</span>
sudo touch /etc/postfix/sasl_passwd
<span class="hljs-built_in">echo</span> <span class="hljs-string">"[smtp.gmail.com]:587 &lt;user@gmail.com&gt;:gmailpass"</span> | sudo tee -a /etc/postfix/sasl_passwd &gt; /dev/null

<span class="hljs-comment"># Secure the SASL password file and update Postfix lookup table</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Securing SASL password file..."</span>
sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd

<span class="hljs-comment"># Allow ports 25 and 587 on firewall</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Allowing ports 25 and 587 on firewall..."</span>
sudo ufw allow out 25
sudo ufw allow out 587

<span class="hljs-comment"># Restart Postfix to apply changes</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Restarting Postfix..."</span>
sudo systemctl restart postfix

<span class="hljs-comment"># Test the Postfix configuration</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Testing Postfix configuration by sending a test email..."</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"If you get this mail, it means the mail application is working"</span> | mail -s <span class="hljs-string">"Postfix mail from &lt;ServerA@domain.com&gt;"</span> &lt;user@gmail.com&gt;

<span class="hljs-comment"># Print mail logs</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Printing mail logs..."</span>
tail /var/<span class="hljs-built_in">log</span>/mail.log

<span class="hljs-comment"># Set up a cron job for daily AIDE checks and email reports</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Setting up daily AIDE checks cron job..."</span>
(crontab -l 2&gt;/dev/null; <span class="hljs-built_in">echo</span> <span class="hljs-string">"0 2 ** * /usr/bin/aide -c /etc/aide/aide.conf --check | mail -s 'AIDE Daily Report' &lt;user@gmail.com&gt;"</span>) | crontab -

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Setup complete. Check your email for the test message and AIDE reports."</span>
</code></pre>
<h4 id="heading-screenshot-showing-email-sent-successfully-from-the-analysis-of-aide-daily-report">Screenshot showing Email sent successfully from the analysis of <code>AIDE Daily Report</code></h4>
<p><img src="https://github.com/user-attachments/assets/a4458d67-7088-45cf-a979-c3a44d7e47ec" alt="image" /></p>
<h3 id="heading-steps-for-conducting-a-security-audit-with-lynis">Steps for Conducting a Security Audit with Lynis</h3>
<ol>
<li><p><strong>Install Lynis</strong></p>
<ul>
<li><p>Open your terminal and update the package list:</p>
<pre><code class="lang-bash">  sudo apt-get update
</code></pre>
</li>
<li><p>Install Lynis:</p>
<pre><code class="lang-bash">  sudo apt-get install -y lynis
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Run a System Audit</strong></p>
<ul>
<li><p>Execute the Lynis system audit: The audit process will take some time and will generate output directly in the terminal. To save the report to a file for easier review, you can redirect the output:</p>
<pre><code class="lang-bash">  sudo lynis audit system &gt; /var/<span class="hljs-built_in">log</span>/lynis-audit.log
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Review the Lynis Report</strong></p>
<ul>
<li><p>Open and review the Lynis report, from the saved log file:</p>
<pre><code class="lang-bash">  sudo tail /var/<span class="hljs-built_in">log</span>/lynis-audit.log
</code></pre>
<p>  <img src="https://github.com/user-attachments/assets/bf284bc0-d13f-4ec2-9106-df609fbd5518" alt="Screenshot 2024-08-09 231213" /></p>
<p>  <img src="https://github.com/user-attachments/assets/ca6a427b-60e6-427a-b3fc-00c43f2f5f54" alt="Screenshot 2024-08-09 231106" /></p>
<p>  <img src="https://github.com/user-attachments/assets/671169e6-1d50-4d73-8311-79731a16fed9" alt="Screenshot 2024-08-09 231129" /></p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-next-we-will-be-reviewing-the-lynis-report-and-address-at-least-5-medium-or-high-risk-findings-and-then-document-the-changes-made-to-fix-the-findings-with-justifications">Next, we will be reviewing the Lynis report, and address at least 5 medium or high-risk findings, and then document the changes made to fix the findings with justifications.</h3>
<h3 id="heading-1-weak-file-permissions-on-critical-directories">1. <strong>Weak File Permissions on Critical Directories</strong></h3>
<ul>
<li><p><strong>Finding</strong>: Directories such as <code>/etc/cron.d</code>, <code>/etc/cron.daily</code>, <code>/etc/cron.hourly</code>, <code>/etc/cron.weekly</code>, and <code>/etc/cron.monthly</code> have permissive permissions.</p>
</li>
<li><p><strong>Impact</strong>: Loose file permissions on these directories could allow unauthorized users to modify scheduled tasks, potentially leading to privilege escalation or system compromise.</p>
</li>
<li><p><strong>Action</strong>: Tighten permissions on these directories.</p>
</li>
<li><p><strong>Steps</strong>:</p>
<ol>
<li><p><strong>Check Current Permissions</strong>:</p>
<pre><code class="lang-bash"> ls -ld /etc/cron.*
</code></pre>
<ul>
<li>Review the permissions to ensure they are not overly permissive.</li>
</ul>
</li>
<li><p><strong>Set Secure Permissions</strong>:</p>
<pre><code class="lang-bash"> sudo chmod 600 /etc/cron.d
 sudo chmod 600 /etc/cron.daily
 sudo chmod 600 /etc/cron.hourly
 sudo chmod 600 /etc/cron.weekly
 sudo chmod 600 /etc/cron.monthly
</code></pre>
</li>
</ol>
</li>
</ul>
<p>    sudo chmod 600 /etc/cron.yearly <code>3. **Verify the Change**:</code> bash ls -ld /etc/cron.* ``` - Ensure the permissions are set to <code>600</code> (i.e., <code>-rw-------</code>), meaning only the root user can read and write.</p>
<ul>
<li><strong>Justification</strong>: Restricting access to cron directories prevents unauthorized users from tampering with scheduled tasks, which is critical for maintaining system integrity.</li>
</ul>
<p><img src="https://github.com/user-attachments/assets/c6550271-1c60-4c5e-a246-f9727c43f117" alt="Screenshot 2024-08-09 233208" /></p>
<h3 id="heading-2-weak-file-permissions-on-sensitive-files">2. <strong>Weak File Permissions on Sensitive Files</strong></h3>
<ul>
<li><p><strong>Finding</strong>: Some files, such as <code>/etc/ssh/sshd_config</code>, and directories like <code>/etc/cron.d</code>, have weak permissions.</p>
</li>
<li><p><strong>Impact</strong>: Inadequate file permissions can allow unauthorized users to modify critical configuration files or execute malicious cron jobs.</p>
</li>
<li><p><strong>Action</strong>: Adjust file and directory permissions to ensure they are secure.</p>
</li>
<li><p><strong>Steps</strong>:</p>
<ol>
<li><p><strong>Check Current Permissions</strong>:</p>
<pre><code class="lang-bash"> ls -l /etc/ssh/sshd_config
</code></pre>
<ul>
<li>Review the permissions to ensure they are not overly permissive.</li>
</ul>
</li>
<li><p><strong>Set Secure Permissions</strong>:</p>
<pre><code class="lang-bash"> sudo chmod 600 /etc/ssh/sshd_config
</code></pre>
</li>
<li><p><strong>Verify the Change</strong>:</p>
<pre><code class="lang-bash"> ls -l /etc/ssh/sshd_config
</code></pre>
<ul>
<li>Ensure the permissions are set to <code>600</code> (i.e., <code>-rw-------</code>), meaning only the root user can read and write.</li>
</ul>
</li>
</ol>
</li>
<li><p><strong>Justification</strong>: Proper permissions help protect sensitive files and configurations from unauthorized access and modification.</p>
</li>
</ul>
<h3 id="heading-3-missing-password-aging-configurations">3. <strong>Missing Password Aging Configurations</strong></h3>
<ul>
<li><p><strong>Finding</strong>: User password aging settings are disabled (<code>/etc/login.defs</code>).</p>
</li>
<li><p><strong>Impact</strong>: Lack of password aging increases the risk of password-related vulnerabilities as passwords may not be changed regularly.</p>
</li>
<li><p><strong>Action</strong>: Enable and configure password aging settings in <code>/etc/login.defs</code> to enforce regular password changes.</p>
</li>
<li><p><strong>Steps</strong>:</p>
<ol>
<li><p><strong>Edit the Login Definitions File</strong>:</p>
<pre><code class="lang-bash"> sudo nano /etc/login.defs
</code></pre>
</li>
<li><p><strong>Configure Password Aging Settings</strong>:</p>
<ul>
<li><p>Set the minimum number of days between password changes:</p>
<pre><code class="lang-bash">  PASS_MIN_DAYS 7
</code></pre>
</li>
<li><p>Set the maximum number of days a password is valid:</p>
<pre><code class="lang-bash">  PASS_MAX_DAYS 90
</code></pre>
</li>
<li><p>Set the number of days before password expiration that the user is warned:</p>
<pre><code class="lang-bash">  PASS_WARN_AGE 10
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Apply the Changes</strong>:</p>
<ul>
<li><p>Apply these settings to all user accounts:</p>
<pre><code class="lang-bash">  sudo chage --mindays 7 --maxdays 90 --warndays 10 ubuntu
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Verify the Settings</strong>:</p>
<pre><code class="lang-bash"> sudo chage -l ubuntu
</code></pre>
<ul>
<li>Ensure the correct password aging policies are applied.</li>
</ul>
</li>
</ol>
</li>
<li><p><strong>Justification</strong>: Enforcing password aging helps ensure that passwords are updated regularly, reducing the risk of compromised accounts.</p>
</li>
</ul>
<p><img src="https://github.com/user-attachments/assets/c6dba8c7-1eca-4009-8823-07633742198f" alt="Screenshot 2024-08-09 233815" /></p>
<p><img src="https://github.com/user-attachments/assets/a83dcc70-4d36-4526-aa82-539ae2d591b9" alt="image" /></p>
<h3 id="heading-4-lack-of-sticky-bit-on-tmp-directory">4. <strong>Lack of Sticky Bit on /tmp Directory</strong></h3>
<ul>
<li><p><strong>Finding</strong>: The sticky bit is not set on the <code>/tmp</code> directory.</p>
</li>
<li><p><strong>Impact</strong>: Without the sticky bit, users can delete or modify files in <code>/tmp</code> that are owned by other users, which could lead to privilege escalation or data tampering.</p>
</li>
<li><p><strong>Action</strong>: Set the sticky bit on the <code>/tmp</code> directory.</p>
</li>
<li><p><strong>Steps</strong>:</p>
<ol>
<li><p><strong>Check Current Permissions</strong>:</p>
<pre><code class="lang-bash"> ls -ld /tmp
</code></pre>
<ul>
<li>This command will show the current permissions of the <code>/tmp</code> directory. Look for a <code>t</code> at the end of the permission string (e.g., <code>drwxrwxrwt</code>), which indicates the sticky bit is set.</li>
</ul>
</li>
<li><p><strong>Set the Sticky Bit</strong>:</p>
<pre><code class="lang-bash"> sudo chmod +t /tmp
</code></pre>
</li>
<li><p><strong>Verify the Change</strong>:</p>
<pre><code class="lang-bash"> ls -ld /tmp
</code></pre>
<ul>
<li>Ensure the sticky bit is now set (<code>drwxrwxrwt</code>).</li>
</ul>
</li>
</ol>
</li>
<li><p><strong>Justification</strong>: Applying the sticky bit restricts file deletions in <code>/tmp</code> to the file's owner, thereby improving security and preventing unauthorized file manipulations.</p>
</li>
</ul>
<p><img src="https://github.com/user-attachments/assets/c39f1d74-48c4-45c6-a88d-98600a40aa72" alt="Screenshot 2024-08-09 234033" /></p>
<h3 id="heading-5-unrestricted-ntp-service-access">5. <strong>Unrestricted NTP Service Access</strong></h3>
<ul>
<li><p><strong>Finding</strong>: NTP (Network Time Protocol) service is running without any access control.</p>
</li>
<li><p><strong>Impact</strong>: An unrestricted NTP service can be abused for DDoS amplification attacks or for manipulating the system clock.</p>
</li>
<li><p><strong>Action</strong>: Configure the NTP service to restrict access.</p>
</li>
<li><p><strong>Steps</strong>:</p>
<ol>
<li><p><strong>Edit the NTP Configuration File</strong>:</p>
<pre><code class="lang-bash"> sudo nano /etc/ntp.conf
</code></pre>
</li>
<li><p><strong>Add Access Control Restrictions</strong>:</p>
<ul>
<li><p>Add the following line to restrict default access:</p>
<pre><code class="lang-bash">  restrict default kod nomodify notrap nopeer noquery
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Restart the NTP Service</strong>:</p>
<pre><code class="lang-bash"> sudo systemctl restart ntp
</code></pre>
</li>
<li><p><strong>Verify the Configuration</strong>:</p>
<pre><code class="lang-bash"> ntpq -p
</code></pre>
<ul>
<li>This command will show the status of the NTP peers and the current configuration.</li>
</ul>
</li>
</ol>
</li>
<li><p><strong>Justification</strong>: Restricting NTP access helps prevent abuse of the service and ensures the system clock's integrity.</p>
</li>
</ul>
<p>These steps will help address the findings identified in the security audit, ensuring the system is better protected against various threats and vulnerabilities.</p>
<h2 id="heading-understanding-cis-benchmarks">Understanding CIS Benchmarks</h2>
<p><strong>CIS (Center for Internet Security) Benchmarks</strong> are consensus-based, best-practice security configuration guides. They are designed to help organizations secure their IT systems and data against cyber threats. These benchmarks are widely recognized as industry standards for hardening systems and improving their security posture.</p>
<h3 id="heading-using-tools-like-oscap-openscap-or-inspec-to-apply-and-check-cis-benchmarks">Using Tools Like oscap (OpenSCAP) or InSpec to Apply and Check CIS Benchmarks</h3>
<p>To run InSpec against a Linux Ubuntu host, follow these steps to install InSpec, run a pre-built CIS benchmark profile, and generate a report.</p>
<h3 id="heading-1-install-inspec-on-the-ubuntu-host">1. <strong>Install InSpec on the Ubuntu Host</strong></h3>
<p>First, you'll need to install InSpec on your Ubuntu system.</p>
<h4 id="heading-a-install-via-omnitruck-script-recommended">A. <strong>Install via Omnitruck Script (Recommended)</strong></h4>
<p>This is the easiest method to install InSpec.</p>
<pre><code class="lang-bash">curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P inspec
</code></pre>
<p><img src="https://github.com/user-attachments/assets/f70310f7-4aab-40a1-9fa8-0a881032c55b" alt="Screenshot 2024-08-12 110005" /></p>
<p><img src="https://github.com/user-attachments/assets/27e87272-7599-47d7-bab5-eb098ed7c5c0" alt="Screenshot 2024-08-12 110139" /></p>
<h4 id="heading-b-install-via-apt-repository-alternative-method">B. <strong>Install via APT Repository (Alternative Method)</strong></h4>
<ol>
<li><p><strong>Add the Chef APT repository:</strong></p>
<pre><code class="lang-bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">"deb [arch=amd64] https://packages.chef.io/repos/apt/stable <span class="hljs-subst">$(lsb_release -cs)</span> main"</span> | sudo tee /etc/apt/sources.list.d/chef-stable.list
</code></pre>
</li>
<li><p><strong>Add the GPG key:</strong></p>
<pre><code class="lang-bash"> curl https://packages.chef.io/chef.asc | sudo apt-key add -
</code></pre>
</li>
<li><p><strong>Update the package list and install InSpec:</strong></p>
<pre><code class="lang-bash"> sudo apt-get update
 sudo apt-get install inspec
</code></pre>
</li>
</ol>
<h3 id="heading-2-obtain-a-cis-benchmark-profile">2. <strong>Obtain a CIS Benchmark Profile</strong></h3>
<p>You can use a pre-built CIS benchmark profile. One such profile is provided by the DevSec Project.</p>
<h4 id="heading-a-download-the-cis-benchmark-profile">A. <strong>Download the CIS Benchmark Profile</strong></h4>
<p>For example, to download and execute the CIS benchmark for Linux:</p>
<pre><code class="lang-bash">inspec supermarket <span class="hljs-built_in">exec</span> dev-sec/linux-baseline
</code></pre>
<p>This command downloads the profile and executes it on your local machine.</p>
<h3 id="heading-3-run-the-inspec-profile-against-the-ubuntu-host">3. <strong>Run the InSpec Profile Against the Ubuntu Host</strong></h3>
<p>Once you have the InSpec profile, you can run it on the host machine.</p>
<h4 id="heading-a-run-the-profile-locally-on-the-ubuntu-host">A. <strong>Run the Profile Locally on the Ubuntu Host</strong></h4>
<pre><code class="lang-bash">inspec <span class="hljs-built_in">exec</span> https://github.com/dev-sec/linux-baseline
git <span class="hljs-built_in">clone</span> https://github.com/dev-sec/linux-baseline.git
<span class="hljs-built_in">cd</span> linux-baseline
inspec <span class="hljs-built_in">exec</span> .
</code></pre>
<p>This command will execute the CIS benchmark checks against your Ubuntu system.</p>
<h4 id="heading-b-run-the-profile-and-generate-a-report">B. <strong>Run the Profile and Generate a Report</strong></h4>
<p>You can generate a report in various formats, such as JSON or HTML, for further analysis.</p>
<ul>
<li><p><strong>Generate an HTML Report:</strong></p>
<pre><code class="lang-bash">  inspec <span class="hljs-built_in">exec</span> https://github.com/dev-sec/linux-baseline --reporter html:report.html
  inspec <span class="hljs-built_in">exec</span> . --reporter html:report.html
</code></pre>
</li>
</ul>
<p><img src="https://github.com/user-attachments/assets/c9ef9c2b-72b5-41ef-b8c7-142c0eae9063" alt="image" /></p>
<ul>
<li><p><strong>Generate a JSON Report:</strong></p>
<pre><code class="lang-bash">  inspec <span class="hljs-built_in">exec</span> dev-sec/linux-baseline --reporter json:report.json
</code></pre>
</li>
</ul>
<h3 id="heading-4-review-the-report">4. <strong>Review the Report</strong></h3>
<ul>
<li><p>If you generated an HTML report, you can ship out the report to your local machine and then open it in a web browser:</p>
</li>
<li><p>If you generated a JSON report, you can parse it or use it as input for other tools or automation processes.</p>
<p>  <img src="https://github.com/user-attachments/assets/fd2c7695-c388-4501-b84a-44327328fa0f" alt="Screenshot 2024-08-12 120733" /></p>
<p>  <img src="https://github.com/user-attachments/assets/99af79df-25b8-405a-8cff-1e5a0d3dc2be" alt="Screenshot 2024-08-12 120852" /></p>
</li>
</ul>
<h3 id="heading-5-optional-schedule-regular-scans">5. <strong>(Optional) Schedule Regular Scans</strong></h3>
<p>You can automate InSpec scans by scheduling them with cron.</p>
<h4 id="heading-a-edit-the-crontab">A. <strong>Edit the Crontab</strong></h4>
<pre><code class="lang-bash">crontab -e
</code></pre>
<h4 id="heading-b-add-a-cron-job-for-regular-scans">B. <strong>Add a Cron Job for Regular Scans</strong></h4>
<p>For example, to run the scan every day at midnight and generate an HTML report:</p>
<pre><code class="lang-bash">0 0 * * * /usr/bin/inspec <span class="hljs-built_in">exec</span> /path/to/linux-baseline --reporter html:/path/to/report-$(date +\%Y-\%m-\%d).html
</code></pre>
<p>This cron job will create a new report file each day, named with the current date.</p>
<h4 id="heading-steps-to-apply-and-check-cis-benchmarks-using-openscap-alternative-to-inspec">Steps to Apply and Check CIS Benchmarks Using OpenSCAP (Alternative to Inspec)</h4>
<ol>
<li><strong>Install OpenSCAP</strong>: sudo apt-get install openscap-scanner openscap-utils</li>
</ol>
<h3 id="heading-check-openscap-version">Check OpenSCAP version</h3>
<pre><code class="lang-bash">oscap -V
</code></pre>
<h3 id="heading-install-scap-security-guide">Install SCAP security guide</h3>
<pre><code class="lang-bash">sudo apt install ssg-debderived ssg-base
</code></pre>
<p>The SSG policies we just installed are located in the /usr/share/xml/scap/ssg/content directory.</p>
<h1 id="heading-download-the-latest-scap-security-guide-from">Download the latest Scap Security Guide from</h1>
<pre><code class="lang-bash">sudo wget https://github.com/ComplianceAsCode/content/releases/download/v0.1.74/scap-security-guide-0.1.74.zip
</code></pre>
<h3 id="heading-install-unzip-if-not-already-pre-installed">Install unzip if not already pre-installed</h3>
<pre><code class="lang-bash">sudo apt install unzip
</code></pre>
<h3 id="heading-unzip-scap-security-guide">Unzip Scap Security Guide</h3>
<pre><code class="lang-bash">sudo unzip scap-security-guide-0.1.74.zip
<span class="hljs-built_in">cd</span> scap-security-guide-0.1.74
</code></pre>
<p>You should now see the SSG security policies for various linux flavors, but we will work with ssg-ubuntu2204-xccdf.xml in our scenario.</p>
<h1 id="heading-display-a-list-of-available-profiles-in-the-selected-security-policy">Display a list of available Profiles in the selected security policy</h1>
<pre><code class="lang-bash">oscap info /usr/share/xml/scap/ssg/content/ssg-ubuntu2204-xccdf.xml
</code></pre>
<p><img src="https://github.com/user-attachments/assets/4fcabd53-f0e8-4d7a-abda-2724c86e6578" alt="image" /></p>
<p>Lets work with <code>xccdf_org.ssgproject.content_profile_cis_level1_server</code> which is tailored for CIS benchmarks Level 1 server hardening.</p>
<h3 id="heading-run-the-evaluation-scan-that-will-output-the-report-in-html-format">Run the evaluation scan that will output the report in html format</h3>
<pre><code class="lang-bash">sudo oscap xccdf <span class="hljs-built_in">eval</span> --profile xccdf_org.ssgproject.content_profile_cis_level1_server --report report.html /usr/share/xml/scap/ssg/content/ssg-ubuntu2204-xccdf.xml
</code></pre>
<p>After the evaluation has completed, you will see a long list of rules and whether your system passed or failed those rules. Copy the <code>result.html</code> file to your local machine and open with web browser.</p>
<p>By following these steps, you'll be able to use InSpec to run CIS benchmark checks against your Ubuntu system, generate reports, and even automate regular compliance checks. By integrating CIS Benchmarks and tools like OpenSCAP into your security practices, you can significantly enhance your system's security posture, ensure compliance with industry standards, and automate the process of securing your IT infrastructure.</p>
<h2 id="heading-next-let-us-put-evrything-we-have-previously-done-into-automation-on-your-chosen-primary-server">Next, let us put evrything we have previously done into automation. On your chosen primary server.</h2>
<p>Here is a bash script containing the steps to install and configure Ansible on an Ubuntu system. I have 1 primary server and 2 other hosts, and ansible will be configured with ssh keys to authenticate to the host servers. Run this script on only the primary server where you want ansible to be installed.</p>
<pre><code class="lang-bash">sudo nano install_ansible.sh
</code></pre>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Install Ansible</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Installing Ansible..."</span>
sudo apt install ansible -y

<span class="hljs-comment"># Verify Ansible installation</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Verifying Ansible installation..."</span>
ansible --version

<span class="hljs-comment"># Create and configure the inventory file</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Configuring Ansible inventory file..."</span>
sudo mkdir /etc/ansible/
sudo touch /etc/ansible/hosts
sudo tee /etc/ansible/hosts &gt; /dev/null &lt;&lt;EOL
[ServerA]
192.168.x.x

[ServerB]
192.168.x.x

[ServerC]
192.168.x.x
EOL

<span class="hljs-comment"># Edit the Ansible configuration file</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Editing Ansible configuration file..."</span>
sudo tee /etc/ansible/ansible.cfg &gt; /dev/null &lt;&lt;EOL
[defaults]
inventory = /etc/ansible/hosts
remote_user = ubuntu

[privilege_escalation]
become = True
become_method = sudo
become_user = root
ask_sudo_pass = False
become_ask_pass = True
EOL

<span class="hljs-comment"># Test Ansible configuration</span>
<span class="hljs-comment">#echo "Testing Ansible configuration..."</span>
<span class="hljs-comment">#ansible all -m ping</span>
<span class="hljs-comment">#</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Ansible installation and configuration complete!"</span>
</code></pre>
<ol>
<li><p><strong>Save the Script:</strong> name it <code>install_</code><a target="_blank" href="http://ansible.sh"><code>ansible.sh</code></a>.</p>
</li>
<li><p><strong>Make the Script Executable:</strong></p>
<pre><code class="lang-bash"> chmod +x install_ansible.sh
</code></pre>
</li>
<li><p><strong>Run the Script:</strong></p>
<pre><code class="lang-bash"> ./install_ansible.sh
</code></pre>
</li>
</ol>
<h3 id="heading-then-we-run-the-ansible-script-to-configure-ansible-hosts-and-authentication-keys">Then we run the ansible script to configure ansible hosts and authentication keys</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># !/bin/bash</span>
<span class="hljs-comment"># Define variables</span>

SSH_KEY_PATH=<span class="hljs-string">"<span class="hljs-variable">$HOME</span>/.ssh/id_rsa"</span>
ANSIBLE_HOSTS=<span class="hljs-string">"/etc/ansible/hosts"</span>
REMOTE_USER=<span class="hljs-string">"ubuntu"</span>

<span class="hljs-comment"># Generate SSH key pair if it doesn't exist</span>

<span class="hljs-keyword">if</span> [ ! -f <span class="hljs-string">"<span class="hljs-variable">$SSH_KEY_PATH</span>"</span> ]; <span class="hljs-keyword">then</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"Generating SSH key pair..."</span>
  ssh-keygen -t rsa -b 4096 -f <span class="hljs-string">"<span class="hljs-variable">$SSH_KEY_PATH</span>"</span> -N <span class="hljs-string">""</span> -C <span class="hljs-string">"<span class="hljs-variable">$REMOTE_USER</span>"</span>
<span class="hljs-keyword">else</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"SSH key pair already exists at <span class="hljs-variable">$SSH_KEY_PATH</span>."</span>
<span class="hljs-keyword">fi</span>

<span class="hljs-comment"># Extract host IPs from Ansible inventory file</span>

HOSTS=$(grep -E <span class="hljs-string">'^\[Server[A-C]\]'</span> <span class="hljs-string">"<span class="hljs-variable">$ANSIBLE_HOSTS</span>"</span> -A 10 | grep -v <span class="hljs-string">'^\['</span> | awk <span class="hljs-string">'{print $1}'</span>)

<span class="hljs-comment"># Copy the SSH key to the target hosts</span>

<span class="hljs-keyword">for</span> HOST <span class="hljs-keyword">in</span> <span class="hljs-variable">$HOSTS</span>; <span class="hljs-keyword">do</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"Copying SSH key to <span class="hljs-variable">$REMOTE_USER</span>@<span class="hljs-variable">$HOST</span>..."</span>

  ssh-copy-id -i <span class="hljs-string">"<span class="hljs-variable">$SSH_KEY_PATH</span>.pub"</span> <span class="hljs-string">"<span class="hljs-variable">$REMOTE_USER</span>@<span class="hljs-variable">$HOST</span>"</span>

  <span class="hljs-keyword">if</span> [ $? -eq 0 ]; <span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Successfully copied SSH key to <span class="hljs-variable">$HOST</span>."</span>
  <span class="hljs-keyword">else</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Failed to copy SSH key to <span class="hljs-variable">$HOST</span>."</span>
  <span class="hljs-keyword">fi</span>
<span class="hljs-keyword">done</span>

<span class="hljs-comment"># Test SSH access</span>

<span class="hljs-keyword">for</span> HOST <span class="hljs-keyword">in</span> <span class="hljs-variable">$HOSTS</span>; <span class="hljs-keyword">do</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"Testing SSH access to <span class="hljs-variable">$REMOTE_USER</span>@<span class="hljs-variable">$HOST</span>..."</span>

  ssh -o PasswordAuthentication=no <span class="hljs-string">"<span class="hljs-variable">$REMOTE_USER</span>@<span class="hljs-variable">$HOST</span>"</span> <span class="hljs-string">"echo 'SSH to <span class="hljs-variable">$HOST</span> successful.'"</span>

  <span class="hljs-keyword">if</span> [ $? -eq 0 ]; <span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"SSH access to <span class="hljs-variable">$HOST</span> confirmed."</span>
  <span class="hljs-keyword">else</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"SSH access to <span class="hljs-variable">$HOST</span> failed."</span>
  <span class="hljs-keyword">fi</span>
<span class="hljs-keyword">done</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"SSH key setup complete."</span>
</code></pre>
<p><img src="https://github.com/user-attachments/assets/f2293700-7b6f-45ec-b700-e9a9866337e6" alt="image" /></p>
<h3 id="heading-below-hardening-yaml-script-includes-both-package-installation-and-configuration-you-may-choose-to-separate-installation-and-configuration-commands-into-separate-tasks-or-separate-yaml-files">Below hardening yaml script includes both package installation and configuration, you may choose to separate installation and configuration commands into separate tasks, or separate yaml files</h3>
<h4 id="heading-run-hardeningscriptyml-to-harden-the-rest-of-the-ansible-hosts">run <code>hardening_script.yml</code> to harden the rest of the ansible hosts</h4>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">System</span> <span class="hljs-string">Hardening</span> <span class="hljs-string">Script</span>
  <span class="hljs-attr">hosts:</span> <span class="hljs-string">all</span>
  <span class="hljs-attr">become:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">tasks:</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Ensure</span> <span class="hljs-string">the</span> <span class="hljs-string">hardening</span> <span class="hljs-string">script</span> <span class="hljs-string">is</span> <span class="hljs-string">present</span> <span class="hljs-string">on</span> <span class="hljs-string">the</span> <span class="hljs-string">target</span> <span class="hljs-string">host</span>
      <span class="hljs-attr">copy:</span>
        <span class="hljs-attr">dest:</span> <span class="hljs-string">/tmp/system_hardening.sh</span>
        <span class="hljs-attr">content:</span> <span class="hljs-string">|
          #!/bin/bash
          echo "Updating the system..."
          apt update
          echo "Disabling root login via SSH..."
          sed -i 's/^PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
          echo "Enabling logging of sudo commands..."
          echo "Defaults logfile=/var/log/sudo.log" &gt;&gt; /etc/sudoers
          echo "Installing and configuring UFW..."
          apt install -y ufw
          ufw default deny incoming
          ufw default allow outgoing
          ufw allow OpenSSH
          ufw enable
          echo "Disabling unused filesystems..."
          echo "install cramfs /bin/true" &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
          echo "install freevxfs /bin/true" &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
          echo "install jffs2 /bin/true" &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
          echo "install hfs /bin/true" &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
          echo "install hfsplus /bin/true" &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
          echo "install udf /bin/true" &gt;&gt; /etc/modprobe.d/disable-filesystems.conf
          echo "Setting strong password policies..."
          apt install -y libpam-pwquality
          sed -i 's/^# minlen.*/minlen = 12/' /etc/security/pwquality.conf
          sed -i 's/^# dcredit.*/dcredit = -1/' /etc/security/pwquality.conf
          sed -i 's/^# ucredit.*/ucredit = -1/' /etc/security/pwquality.conf
          sed -i 's/^# lcredit.*/lcredit = -1/' /etc/security/pwquality.conf
          sed -i 's/^# ocredit.*/ocredit = -1/' /etc/security/pwquality.conf
          echo "Disabling IPv6..."
          sed -i 's/^#net.ipv6.conf.all.disable_ipv6 = 1/net.ipv6.conf.all.disable_ipv6 = 1/' /etc/sysctl.conf
          sysctl -p
          echo "Securing shared memory..."
          echo "tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0" &gt;&gt; /etc/fstab
          echo "Removing unnecessary packages..."
          apt-get autoremove -y --purge
          echo "Installing and configuring rkhunter..."
          apt install -y rkhunter
          rkhunter --update
          rkhunter --propupd
          rkhunter --check --sk
          echo "Setting up log file permissions..."
          chmod -R go-rwx /var/log/*
          echo "Configuring login banner..."
          echo "Authorized access only. All activity may be monitored and reported." &gt; /etc/issue.net
          sed -i 's/^#Banner.*/Banner \/etc\/issue.net/' /etc/ssh/sshd_config
          echo "Setting up limits on user processes..."
          echo "* hard nproc 100" &gt;&gt; /etc/security/limits.conf
          echo "Restricting cron jobs to authorized users..."
          touch /etc/cron.allow
          chmod 600 /etc/cron.allow
          echo "Restricting access to su command..."
          apt install -y libpam-modules
          if ! grep -q "auth required pam_wheel.so use_uid" /etc/pam.d/su; then
              echo "auth required pam_wheel.so use_uid" &gt;&gt; /etc/pam.d/su
          fi
          if ! getent group wheel &gt; /dev/null; then
              echo "Creating 'wheel' group..."
              groupadd wheel
          fi
          echo "Adding 'ubuntu' user to 'wheel' group..."
          usermod -aG wheel ubuntu
          echo "Disabling core dumps..."
          echo "* hard core 0" &gt;&gt; /etc/security/limits.conf
          echo "fs.suid_dumpable = 0" &gt;&gt; /etc/sysctl.conf
          sysctl -p
          echo "Enabling ASLR..."
          echo "kernel.randomize_va_space = 2" &gt;&gt; /etc/sysctl.conf
          sysctl -p
          echo "Restarting SSH service..."
          systemctl restart ssh
          echo "System hardening completed."
</span>        <span class="hljs-attr">mode:</span> <span class="hljs-string">'0755'</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">the</span> <span class="hljs-string">hardening</span> <span class="hljs-string">script</span>
      <span class="hljs-attr">command:</span> <span class="hljs-string">/tmp/system_hardening.sh</span>
</code></pre>
<h3 id="heading-step-2-deploy-and-execute-the-playbook">Step 2: Deploy and Execute the Playbook</h3>
<ol>
<li><p><strong>Save the Playbook</strong>:</p>
<p> Save the playbook as <code>run_hardening_script.yml</code> in your Ansible project directory.</p>
</li>
<li><p><strong>Run the Playbook</strong>:</p>
<p> Execute the playbook using the <code>ansible-playbook</code> command:</p>
<pre><code class="lang-bash"> ansible-playbook run_hardening_script.yml -vv
</code></pre>
</li>
</ol>
<h3 id="heading-to-create-an-ansible-playbook-that-will-install-and-configure-aide-and-postfix">To create an Ansible playbook that will install and configure AIDE and Postfix</h3>
<pre><code class="lang-bash">nano install_aide_postfix.yml
</code></pre>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">and</span> <span class="hljs-string">Configure</span> <span class="hljs-string">AIDE</span> <span class="hljs-string">and</span> <span class="hljs-string">Postfix</span>
  <span class="hljs-attr">hosts:</span> <span class="hljs-string">all</span>
  <span class="hljs-attr">become:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">tasks:</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Ensure</span> <span class="hljs-string">AIDE</span> <span class="hljs-string">and</span> <span class="hljs-string">Postfix</span> <span class="hljs-string">installation</span> <span class="hljs-string">and</span> <span class="hljs-string">configuration</span> <span class="hljs-string">script</span> <span class="hljs-string">is</span> <span class="hljs-string">present</span> <span class="hljs-string">on</span> <span class="hljs-string">the</span> <span class="hljs-string">target</span> <span class="hljs-string">host</span>
      <span class="hljs-attr">copy:</span>
        <span class="hljs-attr">dest:</span> <span class="hljs-string">/tmp/install_aide_postfix.sh</span>
        <span class="hljs-attr">content:</span> <span class="hljs-string">|
          #!/bin/bash
</span>
          <span class="hljs-comment"># Install AIDE</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Installing AIDE..."</span>
          <span class="hljs-string">apt-get</span> <span class="hljs-string">install</span> <span class="hljs-string">-y</span> <span class="hljs-string">aide</span>

          <span class="hljs-comment"># Backup the existing AIDE configuration file</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Backing up AIDE configuration..."</span>
          <span class="hljs-string">cp</span> <span class="hljs-string">/etc/aide/aide.conf</span> <span class="hljs-string">/etc/aide/aide.conf.bkup</span>

          <span class="hljs-comment"># Add exclusions to AIDE configuration file</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Configuring AIDE exclusions..."</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"!/tmp"</span> <span class="hljs-string">|</span> <span class="hljs-string">tee</span> <span class="hljs-string">-a</span> <span class="hljs-string">/etc/aide/aide.conf</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">/dev/null</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"!/var/spool"</span> <span class="hljs-string">|</span> <span class="hljs-string">tee</span> <span class="hljs-string">-a</span> <span class="hljs-string">/etc/aide/aide.conf</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">/dev/null</span>

          <span class="hljs-comment"># Initialize AIDE database</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Initializing AIDE database. This may take a while..."</span>
          <span class="hljs-string">aide</span> <span class="hljs-string">-c</span> <span class="hljs-string">/etc/aide/aide.conf</span> <span class="hljs-string">--init</span>

          <span class="hljs-comment"># Move the new AIDE database to the correct location</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Moving AIDE database..."</span>
          <span class="hljs-string">mv</span> <span class="hljs-string">/var/lib/aide/aide.db.new</span> <span class="hljs-string">/var/lib/aide/aide.db</span>

          <span class="hljs-comment"># Run an AIDE check against the initialized database</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Running AIDE check. This may take a while..."</span>
          <span class="hljs-string">aide</span> <span class="hljs-string">-c</span> <span class="hljs-string">/etc/aide/aide.conf</span> <span class="hljs-string">--check</span>

          <span class="hljs-comment"># Install Postfix</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Installing Postfix..."</span>
          <span class="hljs-string">apt-get</span> <span class="hljs-string">install</span> <span class="hljs-string">-y</span> <span class="hljs-string">postfix</span>

          <span class="hljs-comment"># Configure Postfix for Gmail relay</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Configuring Postfix..."</span>
          <span class="hljs-string">sed</span> <span class="hljs-string">-i</span> <span class="hljs-string">'/^relayhost =/d'</span> <span class="hljs-string">/etc/postfix/main.cf</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"relayhost = [smtp.gmail.com]:587"</span> <span class="hljs-string">|</span> <span class="hljs-string">tee</span> <span class="hljs-string">-a</span> <span class="hljs-string">/etc/postfix/main.cf</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">/dev/null</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"smtp_use_tls = yes"</span> <span class="hljs-string">|</span> <span class="hljs-string">tee</span> <span class="hljs-string">-a</span> <span class="hljs-string">/etc/postfix/main.cf</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">/dev/null</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"smtp_sasl_auth_enable = yes"</span> <span class="hljs-string">|</span> <span class="hljs-string">tee</span> <span class="hljs-string">-a</span> <span class="hljs-string">/etc/postfix/main.cf</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">/dev/null</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd"</span> <span class="hljs-string">|</span> <span class="hljs-string">tee</span> <span class="hljs-string">-a</span> <span class="hljs-string">/etc/postfix/main.cf</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">/dev/null</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"smtp_sasl_security_options = noanonymous"</span> <span class="hljs-string">|</span> <span class="hljs-string">tee</span> <span class="hljs-string">-a</span> <span class="hljs-string">/etc/postfix/main.cf</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">/dev/null</span>

          <span class="hljs-comment"># Create sasl_passwd file for Postfix</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Creating SASL password file..."</span>
          <span class="hljs-string">touch</span> <span class="hljs-string">/etc/postfix/sasl_passwd</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"[smtp.gmail.com]:587 user@gmail.com:gmailpass"</span> <span class="hljs-string">|</span> <span class="hljs-string">tee</span> <span class="hljs-string">-a</span> <span class="hljs-string">/etc/postfix/sasl_passwd</span> <span class="hljs-string">&gt;</span> <span class="hljs-string">/dev/null</span>

          <span class="hljs-comment"># Secure the SASL password file and update Postfix lookup table</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Securing SASL password file..."</span>
          <span class="hljs-string">chmod</span> <span class="hljs-number">600</span> <span class="hljs-string">/etc/postfix/sasl_passwd</span>
          <span class="hljs-string">postmap</span> <span class="hljs-string">/etc/postfix/sasl_passwd</span>

          <span class="hljs-comment"># Allow ports 25 and 587 on firewall</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Allowing ports 25 and 587 on firewall..."</span>
          <span class="hljs-string">ufw</span> <span class="hljs-string">allow</span> <span class="hljs-string">out</span> <span class="hljs-number">25</span>
          <span class="hljs-string">ufw</span> <span class="hljs-string">allow</span> <span class="hljs-string">out</span> <span class="hljs-number">587</span>

          <span class="hljs-comment"># Restart Postfix to apply changes</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Restarting Postfix..."</span>
          <span class="hljs-string">systemctl</span> <span class="hljs-string">restart</span> <span class="hljs-string">postfix</span>

          <span class="hljs-comment"># Test the Postfix configuration</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Testing Postfix configuration by sending a test email..."</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"If you get this mail, it means the mail application is working"</span> <span class="hljs-string">|</span> <span class="hljs-string">mail</span> <span class="hljs-string">-s</span> <span class="hljs-string">"Postfix mail from ServerA@domain.com"</span> <span class="hljs-string">user@gmail.com</span>

          <span class="hljs-comment"># Print mail logs</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Printing mail logs..."</span>
          <span class="hljs-string">tail</span> <span class="hljs-string">/var/log/mail.log</span>

          <span class="hljs-comment"># Set up a cron job for daily AIDE checks and email reports</span>
          <span class="hljs-string">echo</span> <span class="hljs-string">"Setting up daily AIDE checks cron job..."</span>
          <span class="hljs-string">(crontab</span> <span class="hljs-string">-l</span> <span class="hljs-number">2</span><span class="hljs-string">&gt;/dev/null;</span> <span class="hljs-string">echo</span> <span class="hljs-string">"0 2 * * * /usr/bin/aide -c /etc/aide/aide.conf --check | mail -s 'AIDE Daily Report' user@gmail.com"</span><span class="hljs-string">)</span> <span class="hljs-string">|</span> <span class="hljs-string">crontab</span> <span class="hljs-bullet">-</span>

          <span class="hljs-string">echo</span> <span class="hljs-string">"Setup complete. Check your email for the test message and AIDE reports."</span>
      <span class="hljs-attr">mode:</span> <span class="hljs-string">'0755'</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">the</span> <span class="hljs-string">AIDE</span> <span class="hljs-string">and</span> <span class="hljs-string">Postfix</span> <span class="hljs-string">installation</span> <span class="hljs-string">script</span>
      <span class="hljs-attr">command:</span> <span class="hljs-string">/tmp/install_aide_postfix.sh</span>
</code></pre>
<p><strong>Insert your Gmail credentials in the yml above, save and run the Playbook:</strong>:</p>
<pre><code class="lang-bash">ansible-playbook install_aide_postfix.yml
</code></pre>
<h3 id="heading-below-is-an-ansible-playbook-that-will-apply-specific-security-configurations-based-on-cis-benchmarks">Below is an Ansible playbook that will apply specific security configurations based on CIS Benchmarks</h3>
<pre><code class="lang-bash">nano secure_ubuntu.yml
</code></pre>
<pre><code class="lang-bash">---

- name: Apply Security Configurations <span class="hljs-keyword">for</span> Ubuntu Server
  hosts: all
  become: yes

  vars:
    sensitive_files:
      - /etc/passwd
      - /etc/shadow
      - /etc/ssh/sshd_config
      - /etc/gshadow
    unnecessary_services:
      - cups
      - avahi-daemon
      - nfs-server
      - rpcbind
      - vsftpd
    ntp_servers:
      - time.google.com
      - time.cloudflare.com
    secure_delete_tool: <span class="hljs-string">"secure-delete"</span>
    files_to_secure_delete:
      - /tmp/abc.log  <span class="hljs-comment"># Add the path to the file you want to securely delete</span>

  tasks:

  - name: Restrict permissions on sensitive files
      file:
        path: <span class="hljs-string">"{{ item }}"</span>
        owner: root
        group: root
        mode: 0600
      loop: <span class="hljs-string">"{{ sensitive_files }}"</span>
      tags: restrict_permissions

  - name: Disable IPv6 (<span class="hljs-keyword">if</span> not needed)
      sysctl:
        name: net.ipv6.conf.all.disable_ipv6
        value: <span class="hljs-string">'1'</span>
        sysctl_set: yes
        state: present
        reload: yes
      tags: disable_ipv6

  - name: Disable uncommon network protocols
      lineinfile:
        path: /etc/modprobe.d/blacklist.conf
        line: <span class="hljs-string">"blacklist {{ item }}"</span>
        create: yes
      loop:
    - dccp
    - sctp
    - rds
    - tipc
      tags: disable_protocols

  - name: Stop and <span class="hljs-built_in">disable</span> unnecessary services
      service:
        name: <span class="hljs-string">"{{ item }}"</span>
        enabled: no
        state: stopped
      loop: <span class="hljs-string">"{{ unnecessary_services }}"</span>
      tags: disable_services

  - name: Install and configure chrony <span class="hljs-keyword">for</span> NTP synchronization
      apt:
        name: chrony
        state: present
      tags: configure_ntp

  - name: Configure chrony with NTP servers
      lineinfile:
        path: /etc/chrony/chrony.conf
        line: <span class="hljs-string">"server {{ item }} iburst"</span>
        create: yes
        state: present
      loop: <span class="hljs-string">"{{ ntp_servers }}"</span>
      notify:
    - restart chrony
      tags: configure_ntp

  - name: Install secure deletion tool
      apt:
        name: <span class="hljs-string">"{{ secure_delete_tool }}"</span>
        state: present
      tags: secure_delete

  - name: Securely delete files
      <span class="hljs-built_in">command</span>: <span class="hljs-string">"srm -v {{ item }}"</span>
      loop: <span class="hljs-string">"{{ files_to_secure_delete }}"</span>
      when: files_to_secure_delete | length &gt; 0
      tags: secure_delete

  handlers:
  - name: restart chrony
      service:
        name: chrony
        state: restarted
</code></pre>
<ol>
<li><p><strong>Playbook Structure</strong>:</p>
<ul>
<li><p>The playbook is organized into tasks, each of which performs a specific security function.</p>
</li>
<li><p><code>vars</code> are used to define variables for sensitive files, unnecessary services, NTP servers, and files to be securely deleted.</p>
</li>
</ul>
</li>
<li><p><strong>Save and run the Playbook</strong>:</p>
<pre><code class="lang-bash"> ansible-playbook secure_ubuntu.yml
</code></pre>
</li>
<li><p><strong>Customize</strong>:</p>
<ul>
<li><p>Modify the <code>sensitive_files</code>, <code>unnecessary_services</code>, and <code>ntp_servers</code> lists according to your environment's requirements.</p>
</li>
<li><p>Define the <code>files_to_secure_delete</code> list with the paths of files you wish to securely delete.</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-scaling-and-monitoring">Scaling and Monitoring</h2>
<h3 id="heading-lets-set-up-an-ansible-playbook-to-deploy-secure-web-servers-on-2-additional-identical-servers">Let's set up an Ansible playbook to deploy secure web servers on 2 additional identical servers</h3>
<h4 id="heading-playbook-to-installs-and-configures-my-custom-pizza-booking-web-server">Playbook to Installs and configures my custom (pizza booking) web server</h4>
<pre><code class="lang-bash">
nano apache.yml
</code></pre>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">and</span> <span class="hljs-string">Configure</span> <span class="hljs-string">Apache</span> <span class="hljs-string">Web</span> <span class="hljs-string">Server</span>
  <span class="hljs-attr">hosts:</span> <span class="hljs-string">all</span>
  <span class="hljs-attr">become:</span> <span class="hljs-literal">yes</span>

  <span class="hljs-attr">tasks:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Apache</span>
      <span class="hljs-attr">apt:</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">apache2</span>
        <span class="hljs-attr">state:</span> <span class="hljs-string">present</span>
      <span class="hljs-attr">tags:</span> <span class="hljs-string">install_apache</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Ensure</span> <span class="hljs-string">required</span> <span class="hljs-string">Apache</span> <span class="hljs-string">modules</span> <span class="hljs-string">are</span> <span class="hljs-string">enabled</span>
      <span class="hljs-attr">apache2_module:</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">"<span class="hljs-template-variable">{{ item }}</span>"</span>
        <span class="hljs-attr">state:</span> <span class="hljs-string">present</span>
      <span class="hljs-attr">loop:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">ssl</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">rewrite</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">headers</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">expires</span>
      <span class="hljs-attr">tags:</span> <span class="hljs-string">apache_modules</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Configure</span> <span class="hljs-string">firewall</span> <span class="hljs-string">to</span> <span class="hljs-string">allow</span> <span class="hljs-string">HTTP</span> <span class="hljs-string">and</span> <span class="hljs-string">HTTPS</span> <span class="hljs-string">traffic</span>
      <span class="hljs-attr">ufw:</span>
        <span class="hljs-attr">rule:</span> <span class="hljs-string">allow</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">'Apache Full'</span>
      <span class="hljs-attr">tags:</span> <span class="hljs-string">configure_firewall</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Remove</span> <span class="hljs-string">the</span> <span class="hljs-string">default</span> <span class="hljs-string">site</span> <span class="hljs-string">configuration</span>
      <span class="hljs-attr">command:</span> <span class="hljs-string">a2dissite</span> <span class="hljs-number">000</span><span class="hljs-string">-default.conf</span>
      <span class="hljs-attr">notify:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">reload</span> <span class="hljs-string">apache</span>
      <span class="hljs-attr">tags:</span> <span class="hljs-string">remove_default_site</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Create</span> <span class="hljs-string">a</span> <span class="hljs-string">custom</span> <span class="hljs-string">HTML</span> <span class="hljs-string">file</span> <span class="hljs-string">for</span> <span class="hljs-string">the</span> <span class="hljs-string">site</span>
      <span class="hljs-attr">copy:</span>
        <span class="hljs-attr">content:</span> <span class="hljs-string">|
          &lt;!DOCTYPE html&gt;
          &lt;html lang="en"&gt;
          &lt;head&gt;
              &lt;meta charset="UTF-8"&gt;
              &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;
              &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
              &lt;title&gt;Order Your Pizza&lt;/title&gt;
              &lt;style&gt;
                  body { background-color: #f4f4f9; font-family: Arial, sans-serif; margin: 0; padding: 0; color: #333; text-align: center; }
                  header { background-color: #808080; color: white; padding: 20px; }
                  h1 { margin: 0; font-size: 2.5em; }
                  h2 { font-size: 1.5em; margin-top: 0.5em; color: #555; }
                  h3 { font-size: 1.2em; margin-top: 1em; color: #333; }
                  .container { max-width: 800px; margin: 20px auto; padding: 20px; background-color: white; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); }
                  .form-group { margin-bottom: 15px; text-align: left; }
                  .form-group input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; }
                  .toppings { display: flex; justify-content: center; flex-wrap: wrap; }
                  .toppings div { margin: 10px; font-size: 1.1em; }
                  .button { background-color: #4CAF50; border: none; color: white; padding: 15px 25px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 10px; border-radius: 5px; cursor: pointer; transition: background-color 0.3s ease; }
                  .button:hover { background-color: #45a049; }
                  .button.reset { background-color: #e7e7e7; color: black; }
                  .button.reset:hover { background-color: #d5d5d5; }
                  img { max-width: 100%; height: auto; margin-top: 20px; border-radius: 8px; }
                  footer { margin-top: 20px; font-size: 14px; color: #777; }
              &lt;/style&gt;
          &lt;/head&gt;
          &lt;body&gt;
              &lt;header&gt;
                  &lt;h1&gt;Your One Stop Shop for Great Pizzas&lt;/h1&gt;
              &lt;/header&gt;
              &lt;div class="container"&gt;
                  &lt;h2&gt;Kindly Make Your Order by Filling the Details Below&lt;/h2&gt;
                  &lt;form&gt;
                      &lt;div class="form-group"&gt;
                          &lt;label for="name"&gt;Name:&lt;/label&gt;
                          &lt;input type="text" id="name" placeholder="Your Name" required&gt;
                      &lt;/div&gt;
                      &lt;div class="form-group"&gt;
                          &lt;label for="email"&gt;Email:&lt;/label&gt;
                          &lt;input type="email" id="email" placeholder="Your Email" required&gt;
                      &lt;/div&gt;
                      &lt;div class="form-group"&gt;
                          &lt;label for="phone"&gt;Phone No:&lt;/label&gt;
                          &lt;input type="tel" id="phone" placeholder="Your Phone Number" required&gt;
                      &lt;/div&gt;
                      &lt;h3&gt;Select Pizza Toppings&lt;/h3&gt;
                      &lt;div class="toppings"&gt;
                          &lt;div&gt;&lt;input type="checkbox" id="chicken"&gt;&lt;label for="chicken"&gt; Chicken&lt;/label&gt;&lt;/div&gt;
                          &lt;div&gt;&lt;input type="checkbox" id="pepperoni"&gt;&lt;label for="pepperoni"&gt; Pepperoni&lt;/label&gt;&lt;/div&gt;
                          &lt;div&gt;&lt;input type="checkbox" id="sausage"&gt;&lt;label for="sausage"&gt; Sausage&lt;/label&gt;&lt;/div&gt;
                          &lt;div&gt;&lt;input type="checkbox" id="mushrooms"&gt;&lt;label for="mushrooms"&gt; Mushrooms&lt;/label&gt;&lt;/div&gt;
                      &lt;/div&gt;
                      &lt;button type="submit" class="button"&gt;Submit&lt;/button&gt;
                      &lt;button type="reset" class="button reset"&gt;Reset&lt;/button&gt;
                  &lt;/form&gt;
              &lt;/div&gt;
              &lt;img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Pizza-3007395.jpg/1280px-Pizza-3007395.jpg" alt="Pizza"&gt;
              &lt;footer&gt;
                  &lt;h4&gt;All Rights Reserved&lt;/h4&gt;
              &lt;/footer&gt;
          &lt;/body&gt;
          &lt;/html&gt;
</span>        <span class="hljs-attr">dest:</span> <span class="hljs-string">/var/www/html/index.html</span>
        <span class="hljs-attr">mode:</span> <span class="hljs-string">'0644'</span>
      <span class="hljs-attr">tags:</span> <span class="hljs-string">configure_website</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Enable</span> <span class="hljs-string">the</span> <span class="hljs-string">custom</span> <span class="hljs-string">site</span> <span class="hljs-string">configuration</span>
      <span class="hljs-attr">copy:</span>
        <span class="hljs-attr">content:</span> <span class="hljs-string">|
          &lt;VirtualHost *:80&gt;
              DocumentRoot /var/www/html
              &lt;Directory /var/www/html&gt;
                  Options Indexes FollowSymLinks
                  AllowOverride All
                  Require all granted
              &lt;/Directory&gt;
              ErrorLog ${APACHE_LOG_DIR}/error.log
              CustomLog ${APACHE_LOG_DIR}/access.log combined
          &lt;/VirtualHost&gt;
</span>        <span class="hljs-attr">dest:</span> <span class="hljs-string">/etc/apache2/sites-available/custom-site.conf</span>
        <span class="hljs-attr">mode:</span> <span class="hljs-string">'0644'</span>
      <span class="hljs-attr">notify:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">reload</span> <span class="hljs-string">apache</span>
      <span class="hljs-attr">tags:</span> <span class="hljs-string">configure_custom_site</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Enable</span> <span class="hljs-string">the</span> <span class="hljs-string">custom</span> <span class="hljs-string">site</span> <span class="hljs-string">configuration</span>
      <span class="hljs-attr">command:</span> <span class="hljs-string">a2ensite</span> <span class="hljs-string">custom-site.conf</span>
      <span class="hljs-attr">notify:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">reload</span> <span class="hljs-string">apache</span>
      <span class="hljs-attr">tags:</span> <span class="hljs-string">enable_custom_site</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Restart</span> <span class="hljs-string">Apache</span> <span class="hljs-string">to</span> <span class="hljs-string">apply</span> <span class="hljs-string">any</span> <span class="hljs-string">configuration</span> <span class="hljs-string">changes</span>
      <span class="hljs-attr">service:</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">apache2</span>
        <span class="hljs-attr">state:</span> <span class="hljs-string">restarted</span>
      <span class="hljs-attr">tags:</span> <span class="hljs-string">restart_apache</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Display</span> <span class="hljs-string">Apache</span> <span class="hljs-string">status</span>
      <span class="hljs-attr">command:</span> <span class="hljs-string">systemctl</span> <span class="hljs-string">status</span> <span class="hljs-string">apache2</span>
      <span class="hljs-attr">register:</span> <span class="hljs-string">apache_status</span>
      <span class="hljs-attr">changed_when:</span> <span class="hljs-literal">false</span>
      <span class="hljs-attr">tags:</span> <span class="hljs-string">apache_status</span>

  <span class="hljs-attr">handlers:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">reload</span> <span class="hljs-string">apache</span>
      <span class="hljs-attr">service:</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">apache2</span>
        <span class="hljs-attr">state:</span> <span class="hljs-string">reloaded</span>
</code></pre>
<p><strong>Run the Playbook</strong>:</p>
<p>Execute the playbook using the <code>ansible-playbook</code> command:</p>
<pre><code class="lang-bash">ansible-playbook apache.yml -K
</code></pre>
<ul>
<li>You notice a failure on one of the servers, all I had to do was integrate the <code>apt-get update</code> command into the ansible script to make it successful.</li>
</ul>
<p><img src="https://github.com/user-attachments/assets/3dc7ee30-8e77-4deb-9150-ac6cb5ad1a32" alt="image" /></p>
<p><img src="https://github.com/user-attachments/assets/3f57a021-e45a-463a-b3c7-3e9ed569cd85" alt="image" /></p>
<p><img src="https://github.com/user-attachments/assets/cee431bf-b5a7-4124-ac7a-c9412143d35d" alt="image" /></p>
<h3 id="heading-monitoring-with-elk-stack">Monitoring with ELK stack</h3>
<ul>
<li>To implement a central logging solution using the ELK stack (Elasticsearch, Logstash, and Kibana) and create a dashboard or report to overview the security status of all servers, follow these detailed steps. This guide will cover setting up the ELK stack on a central logging server and configuring other servers to send their logs.</li>
</ul>
<h3 id="heading-1-central-logging-server-setup"><strong>1. Central Logging Server Setup</strong></h3>
<h4 id="heading-11-java-environment-packages"><strong>1.1 Java Environment Packages</strong></h4>
<p>Elasticsearch and logstash requires Java to run. Ensure its comes pre-installed once they are installed. Keep below commands and run it to check java version after ELK installation.</p>
<pre><code class="lang-bash">/usr/share/elasticsearch/jdk/bin/java -version
/usr/share/logstash/jdk/bin/java -version
</code></pre>
<h4 id="heading-12-install-and-configure-elasticsearch"><strong>1.2 Install and Configure Elasticsearch</strong></h4>
<pre><code class="lang-bash">sudo apt-get install apt-transport-https
</code></pre>
<ul>
<li>Import the Elasticsearch PGP Key</li>
</ul>
<pre><code class="lang-bash">wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
</code></pre>
<p>Installing from the APT repository:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main"</span> | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
</code></pre>
<pre><code class="lang-bash">sudo apt-get update &amp;&amp; sudo apt-get install elasticsearch
</code></pre>
<h3 id="heading-configure-elasticsearch">Configure Elasticsearch</h3>
<p>Edit the <code>/etc/elasticsearch/elasticsearch.yml</code> file</p>
<pre><code class="lang-bash">cluster.name: my-application
node.name: node-1
path.data: /var/lib/elasticsearch
path.logs: /var/<span class="hljs-built_in">log</span>/elasticsearch
network.host: &lt;ipaddress&gt;
http.port: 9200
discovery.seed_hosts: [<span class="hljs-string">"&lt;&gt;"</span>]
cluster.initial_master_nodes: [<span class="hljs-string">"node-1"</span>]
xpack.security.enabled: <span class="hljs-literal">false</span>
</code></pre>
<h1 id="heading-start-and-enable-elasticsearch">Start and enable Elasticsearch</h1>
<pre><code class="lang-bash">sudo systemctl start elasticsearch
sudo systemctl <span class="hljs-built_in">enable</span> elasticsearch
</code></pre>
<h4 id="heading-check-elasticsearch-logs">Check Elasticsearch logs</h4>
<pre><code class="lang-bash">tail /var/<span class="hljs-built_in">log</span>/elasticsearch/my-application.log
</code></pre>
<h4 id="heading-13-install-and-configure-logstash"><strong>1.3 Install and Configure Logstash</strong></h4>
<pre><code class="lang-bash"><span class="hljs-comment"># Install Logstash</span>
sudo apt install -y logstash

<span class="hljs-comment"># Create Logstash configuration file for Filebeat input</span>
sudo tee /etc/logstash/conf.d/filebeat.conf &gt; /dev/null &lt;&lt;EOF
input {
  beats {
    port =&gt; 5044
  }
}

output {
  elasticsearch {
    hosts =&gt; [<span class="hljs-string">"http://&lt;ipaddress&gt;:9200"</span>]
    index =&gt; <span class="hljs-string">"security-logs-%{+YYYY.MM.dd}"</span>
  }
}
EOF
</code></pre>
<h3 id="heading-start-and-enable-logstash">Start and enable Logstash</h3>
<pre><code class="lang-bash">sudo systemctl start logstash
sudo systemctl <span class="hljs-built_in">enable</span> logstash
sudo systemctl status logstash
</code></pre>
<h4 id="heading-14-install-and-configure-kibana"><strong>1.4 Install and Configure Kibana</strong></h4>
<h4 id="heading-install-kibana">Install Kibana</h4>
<pre><code class="lang-bash">sudo apt install -y kibana
sudo apt-get update &amp;&amp; sudo apt-get install kibana
</code></pre>
<h4 id="heading-configure-kibana-make-modifications-to-etckibanakibanayml-file">Configure Kibana, make modifications to <code>/etc/kibana/kibana.yml</code> file</h4>
<h4 id="heading-uncomment-and-set-serverport">Uncomment and set <code>server.port</code></h4>
<pre><code class="lang-bash">sudo sed -i <span class="hljs-string">'s/#server.port: 5601/server.port: 5601/'</span> /etc/kibana/kibana.yml
</code></pre>
<h4 id="heading-uncomment-and-modify-elasticsearchhosts">Uncomment and modify <code>elasticsearch.hosts</code></h4>
<pre><code class="lang-bash">sudo sed -i <span class="hljs-string">'s/#elasticsearch.hosts: \["http:\/\/localhost:9200"\]/elasticsearch.hosts: \["http:\/\/&lt;ipaddress&gt;:9200"\]/'</span> /etc/kibana/kibana.yml
</code></pre>
<h4 id="heading-uncomment-and-modify-serverhosthttpserverhost">Uncomment and modify <a target="_blank" href="http://server.host"><code>server.host</code></a></h4>
<pre><code class="lang-bash">sudo sed -i <span class="hljs-string">'s/#server.host: "localhost"/server.host: "&lt;ipaddress&gt;"/'</span> /etc/kibana/kibana.yml
</code></pre>
<pre><code class="lang-bash">server.name: <span class="hljs-string">"ServerA"</span>
server.publicBaseUrl: <span class="hljs-string">"http://&lt;ipaddress&gt;:5601"</span>
</code></pre>
<h4 id="heading-start-and-enable-kibana">Start and enable Kibana</h4>
<pre><code class="lang-bash">sudo systemctl start kibana
sudo systemctl <span class="hljs-built_in">enable</span> kibana
sudo systemctl status kibana
</code></pre>
<h4 id="heading-configure-firewall-on-central-logging-server"><strong>Configure firewall on Central Logging Server</strong></h4>
<pre><code class="lang-bash"><span class="hljs-comment"># Allow necessary ports</span>
sudo ufw allow 9200/tcp   <span class="hljs-comment"># Elasticsearch</span>
sudo ufw allow 5601/tcp   <span class="hljs-comment"># Kibana</span>
sudo ufw allow 5044/tcp   <span class="hljs-comment"># Logstash</span>
sudo ufw <span class="hljs-built_in">enable</span>
</code></pre>
<h3 id="heading-install-and-configure-filebeat-on-all-servers-that-will-feed-logs-to-kibana"><strong>Install and Configure Filebeat on All Servers that will feed logs to kibana</strong></h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Install Filebeat</span>
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg

<span class="hljs-built_in">echo</span> <span class="hljs-string">"deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main"</span> | sudo tee /etc/apt/sources.list.d/elastic-8.x.list

sudo apt update
sudo apt install -y filebeat
</code></pre>
<p>Edit the Filebeat configuration file <code>/etc/filebeat/filebeat.yml</code> on each server:</p>
<ul>
<li>setting up filebeat to ship logs to elastic search,</li>
</ul>
<pre><code class="lang-bash">output.elasticsearch:
  hosts: [<span class="hljs-string">"&lt;ipaddress&gt;:9200"</span>]
  username: <span class="hljs-string">"kibana_user"</span>
  password: <span class="hljs-string">"passw"</span>

setup.kibana:
    host: <span class="hljs-string">"&lt;ipaddress&gt;:5601"</span>
    username: <span class="hljs-string">"kibana_user"</span>  
    password: <span class="hljs-string">"passw"</span>
</code></pre>
<h4 id="heading-but-if-setting-up-filebeat-to-ship-logs-through-logstash-uncomment-and-modify-the-outputlogstash-section-but-note-that-outputlogstash-and-outputelasticsearch-cannot-be-enabled-at-same-time">But if setting up filebeat to ship logs through logstash, uncomment and modify the <code>output.logstash</code> section: but note that <code>output.logstash</code> and <code>output.elasticsearch</code> cannot be enabled at same time.</h4>
<pre><code class="lang-bash"><span class="hljs-comment"># output.logstash</span>
<span class="hljs-comment"># The Logstash hosts</span>
  <span class="hljs-comment">#hosts: ["&lt;ipaddress&gt;:5044"]</span>
</code></pre>
<h4 id="heading-list-the-available-modules">List the available modules:</h4>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /usr/share/filebeat/bin
filebeat modules list
</code></pre>
<p>I have installed apache previously so we’re going to configure Filebeat to ship apache logs, system logs and authentication logs.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /etc/filebeat/modules.d
filebeat modules <span class="hljs-built_in">enable</span> apache
</code></pre>
<pre><code class="lang-bash">nano /etc/filebeat/modules.d/apache.yml
</code></pre>
<pre><code class="lang-bash">- module: apache

<span class="hljs-comment"># Access logs</span>

  access:
    enabled: <span class="hljs-literal">true</span>
    var.paths:
      - /var/<span class="hljs-built_in">log</span>/apache2/access.log*

<span class="hljs-comment"># Error logs</span>

  error:
    enabled: <span class="hljs-literal">true</span>
    var.paths:
      - /var/<span class="hljs-built_in">log</span>/apache2/error.log*
</code></pre>
<pre><code class="lang-bash">filebeat modules <span class="hljs-built_in">enable</span> system
</code></pre>
<pre><code class="lang-bash">nano /etc/filebeat/modules.d/system.yml
</code></pre>
<pre><code class="lang-bash">- module: system

<span class="hljs-comment"># Syslog</span>

  syslog:
    enabled: <span class="hljs-literal">true</span>
    var.paths:
      - /var/<span class="hljs-built_in">log</span>/syslog*

<span class="hljs-comment"># Authorization logs</span>

  auth:
    enabled: <span class="hljs-literal">true</span>
    var.paths:
      - /var/<span class="hljs-built_in">log</span>/auth.log*
</code></pre>
<p>Below can be used if it were nginx server that was installed.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /usr/share/filebeat/bin
filebeat modules <span class="hljs-built_in">enable</span> nginx
</code></pre>
<pre><code class="lang-bash">nano /etc/filebeat/modules.d/nginx.yml
</code></pre>
<pre><code class="lang-bash">- module: nginx
  access:
    enabled: <span class="hljs-literal">true</span>
    var.paths: [<span class="hljs-string">"/var/log/nginx/access.log*"</span>]
</code></pre>
<p>Test that the configuration is okay</p>
<pre><code class="lang-bash">$ sudo filebeat <span class="hljs-built_in">test</span> config
sudo filebeat <span class="hljs-built_in">test</span> config -e
Config OK
</code></pre>
<h4 id="heading-23-start-and-enable-filebeat-on-all-servers"><strong>2.3 Start and Enable Filebeat on All Servers</strong></h4>
<pre><code class="lang-bash"><span class="hljs-comment"># Start and enable Filebeat</span>
sudo systemctl start filebeat
sudo systemctl <span class="hljs-built_in">enable</span> filebeat
sudo systemctl status filebeat
</code></pre>
<h4 id="heading-24-adjust-firewall-on-all-servers-if-enabled"><strong>2.4 Adjust Firewall on All Servers if enabled</strong></h4>
<ul>
<li>Ensure UFW allows traffic to and from the Central Logging Server:</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-comment"># Allow traffic to the Central Logging Server</span>
sudo ufw allow 5044/tcp   <span class="hljs-comment"># Logstash</span>
sudo ufw <span class="hljs-built_in">enable</span>
</code></pre>
<ul>
<li>Test for connectivity amongst all filebeats host servers</li>
</ul>
<pre><code class="lang-bash">curl -X GET <span class="hljs-string">"&lt;ipaddress&gt;:9200/"</span>
curl -I &lt;http://&lt;ipaddress&gt;:5601&gt; [firewall]
</code></pre>
<h3 id="heading-create-dashboards-and-reports-in-kibana-run-this-on-central-logging-server-only"><strong>Create Dashboards and Reports in Kibana</strong> [Run this on central logging server only]</h3>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /usr/share/filebeat/bin
sudo filebeat setup --dashboards
</code></pre>
<ul>
<li>Enable default dashboard</li>
</ul>
<pre><code class="lang-bash">sudo filebeat setup -e
</code></pre>
<h4 id="heading-41-access-kibana"><strong>4.1 Access Kibana</strong></h4>
<ul>
<li><p>Open your web browser and navigate to <code>http://&lt;ipaddress&gt;:5601</code>.</p>
</li>
<li><p>In the side navigation, click Discover. To see Filebeat data, make sure the predefined filebeat-* data view is selected.</p>
</li>
<li><p>If you don’t see data in Kibana, try changing the time filter to a larger range. By default, Kibana shows the last 15 minutes.</p>
</li>
<li><p>In the side navigation, click Dashboard, then select the dashboard that you want to open.</p>
<p>  <strong>syslog dashboard</strong></p>
</li>
<li><p><img src="https://github.com/user-attachments/assets/69b79df6-52b4-413a-97cf-8a795d502649" alt="Screenshot 2024-08-14 125932" /></p>
<p>  <strong>ssh login dashboard</strong></p>
</li>
<li><p><img src="https://github.com/user-attachments/assets/25293241-aa0c-4adb-bf9c-57f5091bbb62" alt="Screenshot 2024-08-14 130933" /></p>
<p>  <strong>sudo commands dashboard</strong></p>
</li>
<li><p><img src="https://github.com/user-attachments/assets/34060b0a-c89c-458f-96b1-8b89ebc56636" alt="Screenshot 2024-08-14 131206" /></p>
</li>
<li><p>Optionally, Configure your visualization to display the status data you are interested in (e.g., number of failed login attempts), select a pre-set dashboard and Add visualizations, Click <strong>Save</strong>.</p>
</li>
</ul>
<p>In wrapping up, the journey of securing and automating cloud servers is a critical aspect of modern DevOps practices. Through meticulous server hardening, continuous monitoring, and strategic use of automation tools like Ansible, we've crafted a resilient and scalable infrastructure. This process not only fortifies your servers against vulnerabilities but also enhances efficiency and consistency across deployments. By adopting these best practices, your infrastructure would be positioned to maintain a secure, reliable, and scalable environment, enabling you to confidently support your company's growth and technological advancements.</p>
]]></content:encoded></item><item><title><![CDATA[The Value of Network Administration Skills in Cloud Computing]]></title><description><![CDATA[In the cloud computing era, network administration skills are invaluable. Hybrid and multi-cloud environments require traditional networking knowledge to integrate on-premises infrastructure with cloud services. Cloud networking concepts like VLANs, ...]]></description><link>https://devblog.seunb.com/the-value-of-network-administration-skills-in-cloud-computing</link><guid isPermaLink="true">https://devblog.seunb.com/the-value-of-network-administration-skills-in-cloud-computing</guid><category><![CDATA[Linux]]></category><category><![CDATA[ansible-playbook]]></category><category><![CDATA[nmap]]></category><category><![CDATA[snort]]></category><category><![CDATA[vmware]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[networking]]></category><category><![CDATA[dhcp]]></category><category><![CDATA[dns]]></category><category><![CDATA[NTP ]]></category><category><![CDATA[tcpdump]]></category><category><![CDATA[vpn]]></category><dc:creator><![CDATA[Seun B]]></dc:creator><pubDate>Thu, 08 Aug 2024 17:11:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724617295244/fcd9f8a1-9618-4da0-8540-d53635d7f2e9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the cloud computing era, network administration skills are invaluable. Hybrid and multi-cloud environments require traditional networking knowledge to integrate on-premises infrastructure with cloud services. Cloud networking concepts like VLANs, subnets, routing, and firewalls are essential.</p>
<p>Network security skills apply directly to cloud security measures. Understanding containerization, microservices, and Infrastructure as Code (IaC) is crucial. Network troubleshooting, edge computing, compliance, cost optimization, and cloud-native networking all benefit from a strong foundation in traditional networking principles.</p>
<p>Lets picture a scenario where an organization is opening a new branch office and needs to set up a secure network infrastructure that integrates with the main office. As a Cloud Platform Engineer, you’re tasked with designing, implementing, and automating this setup. I will be running through a step by step process of how to achieve this using a vmware worksation. The concept remains the same whether you use on-prem or cloud resources.</p>
<h1 id="heading-deploying-3-vms-using-vmware-workstation"><strong>Deploying 3 VMs Using VMware Workstation</strong></h1>
<h1 id="heading-network-architecture-diagram"><strong>Network Architecture Diagram:</strong></h1>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*GqZmWzBbhNDIzGIo" alt /></p>
<p>A Simple Network Architecture</p>
<h1 id="heading-diagram-details"><strong>Diagram Details:</strong></h1>
<ul>
<li><p><strong>Main Office VPN Gateway</strong>: Connects to the Branch Router via a VPN tunnel.</p>
</li>
<li><p><strong>Branch Router</strong>: Provides internet access and routes traffic between the branch office and the main office via the VPN tunnel.</p>
</li>
<li><p><strong>Branch Switch</strong>: Central hub connecting all devices within the branch office.</p>
</li>
<li><p><strong>Peripheral Devices</strong>: Connected directly to the Branch Switch.</p>
</li>
<li><p><strong>Branch Server</strong>: Manages DNS, VPN, DHCP, and NTP services.</p>
</li>
<li><p><strong>Client Desktops</strong>: Connect to the Branch Switch to access network resources and services.</p>
</li>
</ul>
<h1 id="heading-using-vmware-workstation-i-took-the-steps-below-to-deploy-3-vms-and-achieve-the-network-configuration"><strong>Using VMware Workstation, I took the steps below to deploy 3 VMs and achieve the network configuration:</strong></h1>
<h1 id="heading-create-three-vms"><strong>Create Three VMs</strong></h1>
<p>Create three VMs using VMware Workstation and a predefined VMDK disk (located at <a target="_blank" href="https://www.osboxes.org/ubuntu/#ubuntu-24-04-vmware">OSBoxes</a>),<a target="_blank" href="https://www.osboxes.org/ubuntu/#ubuntu-24-04-vmware">https://www.osboxes.org/ubuntu/#ubuntu-24-04-vmware</a> follow these steps:</p>
<ol>
<li><p><strong>Open VMware Workstation</strong></p>
</li>
<li><p>Start VMware Workstation on your machine.</p>
</li>
<li><p><strong>Create a New Virtual Machine</strong></p>
</li>
<li><p>For each of the three VMs (Main Office Server, Branch Office Server, and Client VM), follow these steps:</p>
</li>
</ol>
<ul>
<li><p><strong>Select File &gt; New Virtual Machine…</strong></p>
</li>
<li><p><strong>Specify Disk File</strong></p>
</li>
<li><p>Select <code>I will install the operating system later</code> and click <code>next</code>.</p>
</li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:956/0*D2k47lR_wq1El4lD" alt /></p>
<ul>
<li><p>Select a guest operating system <code>Linux</code> and version <code>ubuntu</code></p>
</li>
<li><p>Choose the location where you have kept the custom .vmdk file Complete the setup and click <code>finish</code></p>
</li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1037/0*1l1EVJqnHu7ShVTr" alt /></p>
<ul>
<li><p><strong>Name the Virtual Machine</strong></p>
</li>
<li><p>Give a name to the virtual machine, e.g., “Main Office Server,” “Branch Office Server,” or “Client VM.” Specify the location where you want to store the VM files.</p>
</li>
<li><p><strong>Finish</strong></p>
</li>
<li><p>Click “Finish” to complete the VM creation process.</p>
</li>
<li><p>Repeat these steps for each of the three VMs.</p>
<ul>
<li>Now select a virtual machine, click on <code>VM</code> then <code>settings</code>, this opens the VM properties, click <code>Add</code>, select <code>hard disk</code>, <code>scsi</code>, <code>use an existing virtual disk</code>, browse for location of disk and click <code>finish</code>.</li>
</ul>
</li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*EkMXqEyMblacq8k6" alt /></p>
<p>Now you can start the VM with the imported disk [.vmdk file] you have selected.</p>
<h1 id="heading-network-configuration"><strong>Network Configuration</strong></h1>
<h1 id="heading-create-virtual-networks"><strong>Create Virtual Networks</strong></h1>
<ol>
<li><strong>Create Virtual Networks in VMware Workstation:</strong></li>
</ol>
<p><strong>MainOfficeNet:</strong></p>
<ol>
<li><p>Open VMware Workstation.</p>
</li>
<li><p>Go to <code>Edit</code> &gt; <code>Virtual Network Editor</code>.</p>
</li>
<li><p>Click <code>Add Network</code> and select a network (e.g., <code>VMnet2</code>).</p>
</li>
<li><p>Set the network to <code>Host-only</code>.</p>
</li>
<li><p>Set the subnet IP to <code>192.168.1.0</code> and the subnet mask to <code>255.255.255.0</code>.</p>
</li>
<li><p>Disable the DHCP for this network.</p>
</li>
<li><p>Rename VMnet3 to MainOfficeNet.</p>
</li>
</ol>
<ul>
<li><strong>BranchOfficeNet:</strong></li>
</ul>
<ol>
<li><p>Follow the same steps to create another network (e.g., <code>VMnet3</code>).</p>
</li>
<li><p>Set the network to <code>Host-only</code>.</p>
</li>
<li><p>Set the subnet IP to <code>192.168.5.0</code> and the subnet mask to <code>255.255.255.0</code>.</p>
</li>
<li><p>Disable the DHCP for this network.</p>
</li>
<li><p>Rename VMnet3 to BranchOfficeNet.</p>
</li>
</ol>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*SWlCe-RJ2ZTG2Y9F" alt /></p>
<ol>
<li><strong>Assign Networks to VMs:</strong></li>
</ol>
<ul>
<li><strong>Main Office Server:</strong></li>
</ul>
<ol>
<li><p>Go to the settings of the Main Office Server VM.</p>
</li>
<li><p>Under <code>Network Adapter</code>, add the network adapter.</p>
</li>
<li><p>Attach the adapter to <code>VMnet2 (MainOfficeNet)</code>.</p>
</li>
</ol>
<ul>
<li><strong>Branch Office Server:</strong></li>
</ul>
<ol>
<li><p>Go to the settings of the Branch Office Server VM.</p>
</li>
<li><p>Under <code>Network Adapter</code>, add the network adapters.</p>
</li>
<li><p>Attach the adapter to <code>VMnet3 (BranchOfficeNet)</code>.</p>
</li>
</ol>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*gFcVYj3Ao8isoUX8" alt /></p>
<ul>
<li><strong>Client VM:</strong></li>
</ul>
<ol>
<li><p>Go to the settings of the Client VM.</p>
</li>
<li><p>Under <code>Network Adapter</code>, attach the adapter to <code>VMnet3 (BranchOfficeNet)</code>.</p>
</li>
<li><p><strong>Power On the VMs</strong></p>
</li>
<li><p>Power on each VM by right-clicking each VM and selecting “Power On.”</p>
</li>
</ol>
<h1 id="heading-configure-network-interfaces"><strong>Configure Network Interfaces</strong></h1>
<h2 id="heading-updating-or-replacing-existing-connections"><strong>Updating or Replacing Existing Connections</strong></h2>
<ol>
<li><strong>Identify and Modify Existing Connections</strong></li>
</ol>
<ul>
<li><strong>Delete Existing Connections:</strong></li>
</ul>
<pre><code class="lang-plaintext">sudo nmcli con delete netplan-ens33 
sudo nmcli con delete 'Wired connection 1'
</code></pre>
<ul>
<li><p><strong>Add New Connections:</strong></p>
</li>
<li><p><code>Add MainOfficeNet to ens33</code></p>
</li>
</ul>
<pre><code class="lang-plaintext">sudo nmcli con add type ethernet ifname ens33 con-name MainOfficeNet ip4 192.168.1.10/24
</code></pre>
<ol>
<li><strong>Apply and Bring Up Connections</strong></li>
</ol>
<ul>
<li><p><strong>Bring Up the Connection:</strong></p>
</li>
<li><p><code>sudo nmcli con up MainOfficeNet</code></p>
</li>
</ul>
<ol>
<li><p><strong>Restart NetworkManager</strong></p>
</li>
<li><p>Restart NetworkManager to apply the changes:</p>
</li>
</ol>
<pre><code class="lang-plaintext">sudo systemctl restart NetworkManager
</code></pre>
<h1 id="heading-configuration-for-branch-office-server"><strong>Configuration for Branch Office Server</strong></h1>
<p><strong>Configure Network Interfaces:</strong></p>
<ul>
<li><strong>Delete Existing Connections:</strong></li>
</ul>
<pre><code class="lang-plaintext">sudo nmcli con delete netplan-ens33 
sudo nmcli con delete 'Wired connection 1'
</code></pre>
<ul>
<li><p><strong>Add New Connections:</strong></p>
</li>
<li><p><code># Add BranchOfficeNet to ens33</code></p>
</li>
</ul>
<pre><code class="lang-plaintext">sudo nmcli con add type ethernet ifname ens33 con-name BranchOfficeNet ip4 192.168.5.10/24
</code></pre>
<ol>
<li><strong>Bring Up the Connections:</strong></li>
</ol>
<ul>
<li><code>sudo nmcli con up BranchOfficeNet</code></li>
</ul>
<ol>
<li>Verify the configuration:</li>
</ol>
<pre><code class="lang-plaintext">nmcli con show 
nmcli con show --active 
ip addr show 
ifconfig -a
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*lwKEK1S_EzXhRn2q" alt /></p>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*VFdL39QPLAYryNSF" alt /></p>
<h1 id="heading-configuration-for-client-vm"><strong>Configuration for Client VM</strong></h1>
<ol>
<li><strong>Delete Existing Connections:</strong></li>
</ol>
<ul>
<li><code>sudo nmcli con delete 'Wired connection 1'</code></li>
</ul>
<p><strong>Add DHCP Configuration:</strong></p>
<ul>
<li><code>nmcli con add type ethernet ifname ens33 con-name BranchOfficeNet ipv4.method auto</code></li>
</ul>
<p><strong>Bring Up the Connection:</strong></p>
<ul>
<li><code>sudo nmcli con up BranchOfficeNet</code></li>
</ul>
<h1 id="heading-verify-configuration"><strong>Verify Configuration</strong></h1>
<ul>
<li><p>From the Client VM, ensure it gets an IP address via DHCP and check connectivity:</p>
</li>
<li><p><code>nmcli device show ens33 ip route ip addr</code></p>
</li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*zbaZEKqWJaeDZwL3" alt /></p>
<h1 id="heading-setting-up-dns"><strong>Setting Up DNS:</strong></h1>
<h2 id="heading-setting-up-dns-with-bind9-involves-configuring-both-the-main-and-branch-servers-to-handle-local-domain-resolution-and-forward-external-queries-appropriately-below-are-the-detailed-steps-for-setting-this-up"><strong>Setting up DNS with BIND9 involves configuring both the main and branch servers to handle local domain resolution and forward external queries appropriately. Below are the detailed steps for setting this up.</strong></h2>
<h1 id="heading-main-server-mainabclocal"><strong>Main Server (main.abc.local)</strong></h1>
<h2 id="heading-1-install-bind9"><strong>1. Install BIND9</strong></h2>
<pre><code class="lang-plaintext">sudo apt update
sudo apt install bind9 bind9utils bind9-doc -y
</code></pre>
<h2 id="heading-2-configure-bind9"><strong>2. Configure BIND9</strong></h2>
<p>Edit the BIND9 configuration files to set up the master server:</p>
<ul>
<li><p><strong>Edit named.conf.local</strong></p>
</li>
<li><p><code>sudo nano /etc/bind/named.conf.local</code></p>
</li>
</ul>
<p>Add the following:</p>
<pre><code class="lang-plaintext">zone "abc.local" {
    type master;
    file "/etc/bind/db.abc.local";
};

zone "5.168.192.in-addr.arpa" {
    type master;
    file "/etc/bind/db.192.168.5";
};
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*oqkZG3P3A6roCzgy" alt /></p>
<p><strong>Create Zone Files</strong></p>
<ul>
<li><p>Create the forward zone file for <code>abc.local</code>:</p>
</li>
<li><p><code>sudo nano /etc/bind/db.abc.local</code></p>
</li>
</ul>
<p>Add the following content:</p>
<pre><code class="lang-plaintext">$TTL    604800
@       IN      SOA     main.abc.local. admin.abc.local. (
                             2         ; Serial
                        604800         ; Refresh
                         86400         ; Retry
                       2419200         ; Expire
                        604800 )       ; Negative Cache TTL
;
@       IN      NS      main.abc.local.
main    IN      A       192.168.1.10
branch  IN      A       192.168.5.10
client  IN      A       192.168.5.15
</code></pre>
<ul>
<li><p>Create the reverse zone file for <code>192.168.5.x</code>:</p>
</li>
<li><p><code>sudo nano /etc/bind/db.192.168.5</code></p>
</li>
<li><p>Add the following content:</p>
</li>
</ul>
<pre><code class="lang-plaintext">$TTL    604800
@       IN      SOA     main.abc.local. admin.abc.local. (
                             2         ; Serial
                        604800         ; Refresh
                         86400         ; Retry
                       2419200         ; Expire
                        604800 )       ; Negative Cache TTL
;
@       IN      NS      main.abc.local.
10      IN      PTR     branch.abc.local.
15      IN      PTR     client.abc.local.
</code></pre>
<h2 id="heading-3-configure-forwarders"><strong>3. Configure Forwarders</strong></h2>
<p>Edit named.conf.options to include forwarders:</p>
<pre><code class="lang-plaintext">sudo nano /etc/bind/named.conf.options
</code></pre>
<p>Add the following within the <code>options</code> block:</p>
<pre><code class="lang-plaintext">options {
    directory "/var/cache/bind";

    forwarders {
        8.8.8.8;  // Google's DNS
        8.8.4.4;  // Google's DNS
    };

    dnssec-validation auto;

    listen-on-v6 { any; };
};
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*UJ-WsoiLDPzfsObr" alt /></p>
<h2 id="heading-4-restart-bind9"><strong>4. Restart BIND9</strong></h2>
<pre><code class="lang-plaintext">sudo systemctl restart bind9
systemctl status bind9
systemctl restart named.service
</code></pre>
<h1 id="heading-branch-server-branchabclocal"><strong>Branch Server (branch.abc.local)</strong></h1>
<h2 id="heading-1-install-bind9-1"><strong>1. Install BIND9</strong></h2>
<pre><code class="lang-plaintext">sudo apt update
sudo apt install bind9 bind9utils bind9-doc -y
</code></pre>
<h1 id="heading-configure-iptables-to-permit-incoming-dns-queries-from-client-systems"><strong>Configure iptables to permit incoming dns queries from client systems.</strong></h1>
<h2 id="heading-allow-incoming-dns-traffic-on-port-53-udp"><strong>Allow incoming DNS traffic on port 53 (UDP)</strong></h2>
<pre><code class="lang-plaintext">sudo iptables -A INPUT -p udp - dport 53 -j ACCEPT
</code></pre>
<h2 id="heading-allow-incoming-dns-traffic-on-port-53-tcp"><strong>Allow incoming DNS traffic on port 53 (TCP)</strong></h2>
<pre><code class="lang-plaintext">sudo iptables -A INPUT -p tcp - dport 53 -j ACCEPT
</code></pre>
<h1 id="heading-save-the-iptables-rules"><strong>Save the iptables rules</strong></h1>
<p>sudo sh -c “iptables-save &gt; /etc/iptables/rules.v4”</p>
<h2 id="heading-2-configure-bind9-as-slave"><strong>2. Configure BIND9 as Slave</strong></h2>
<p>Edit the BIND9 configuration files to set up the branch server:</p>
<ul>
<li><p><strong>Edit named.conf.local</strong></p>
</li>
<li><p><code>sudo nano /etc/bind/named.conf.local</code></p>
</li>
<li><p>Add the following:</p>
</li>
</ul>
<pre><code class="lang-plaintext">zone "abc.local" {
    type slave;
    file "/var/cache/bind/db.abc.local";
    masters { 192.168.1.10; };
};

zone "5.168.192.in-addr.arpa" {
    type slave;
    file "/var/cache/bind/db.192.168.5";
    masters { 192.168.1.10; };
};
</code></pre>
<ul>
<li><p><strong>Configure Forwarding</strong></p>
</li>
<li><p>Edit named.conf.options to forward unknown/external queries to the main server:</p>
</li>
<li><p><code>sudo nano /etc/bind/named.conf.options</code></p>
</li>
<li><p>Add the following within the <code>options</code> block:</p>
</li>
</ul>
<pre><code class="lang-plaintext">options {
    directory "/var/cache/bind";

    forwarders {
        192.168.1.10;  // Main server's IP
    };

    dnssec-validation auto;

    listen-on-v6 { any; };
};
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1023/0*1LUa9XNCvWBBDAXM" alt /></p>
<h2 id="heading-3-restart-and-enable-bind9-service-at-every-system-reboot"><strong>3. Restart and enable BIND9 service at every system reboot</strong></h2>
<pre><code class="lang-plaintext">sudo systemctl restart bind9
sudo systemctl enable bind9
</code></pre>
<h2 id="heading-check-zone-transfer-logs-on-branch-server"><strong>Check Zone Transfer Logs on Branch Server</strong></h2>
<pre><code class="lang-plaintext">sudo systemctl status bind9
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*I7t6X8HncTcbWYLE" alt /></p>
<h2 id="heading-test-dns-resolution"><strong>Test DNS Resolution</strong></h2>
<p>On the branch server, use <code>dig</code> to test:</p>
<pre><code class="lang-plaintext">dig main.abc.local @localhost
dig branch.abc.local @localhost
dig client.abc.local @localhost
dig google.com @localhost
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*8BD9S_mdpQLscyUm" alt /></p>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*uEchbe6aQb-RNSJn" alt /></p>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*gR9hq-A0FrjQ5Irj" alt /></p>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*cltzuJIeOUQ_V1vW" alt /></p>
<p>The dig output indicates that the DNS server running on localhost successfully resolved the domain main.abc.local to the IP address 192.168.1.10, but it issued a warning because .local is reserved for mDNS. The query was handled correctly with an authoritative answer and the response took 4 milliseconds.</p>
<p>The dig output indicates that the DNS server running on localhost successfully resolved google.com to the IP address 142.251.32.78. The query was handled correctly with an authoritative answer, and the response took 1 millisecond. The result shows that your local DNS server is capable of resolving external domain names as well, as it is properly configured to forward queries or perform DNS resolution.</p>
<p>By following these steps, your branch server will be configured to resolve local domain queries from its own zone files and forward any unknown or external domain queries to the main server. The main server is configured to forward external queries to public DNS servers (like Google’s DNS).</p>
<h1 id="heading-client-configuration-192168515"><strong>Client Configuration (192.168.5.15)</strong></h1>
<p>Ensure that the client machine is configured to use the branch office DNS server for its DNS queries.</p>
<p>Setup # operation for /etc/resolv.conf.</p>
<p>nameserver 192.168.5.10 nameserver 127.0.0.53 options edns0 trust-ad search branch.company.local</p>
<ol>
<li><p><strong>Configure</strong><code>/etc/netplan/01-netcfg.yaml</code></p>
</li>
<li><p>Edit the netplan configuration to use the branch server for DNS:</p>
</li>
</ol>
<ul>
<li><code>sudo nano /etc/netplan/01-netcfg.yaml</code></li>
</ul>
<ol>
<li>Ensure it contains:</li>
</ol>
<pre><code class="lang-plaintext">
network:
  version: 2
  ethernets:
    ens33:
      dhcp4: yes
      routes:
        - to: default
          via: 192.168.5.10
      nameservers:
        addresses:
          - 192.168.5.10
          - 8.8.8.8
</code></pre>
<p>Apply the Netplan configuration:</p>
<pre><code class="lang-plaintext">sudo netplan apply
</code></pre>
<h1 id="heading-verify-the-setup"><strong>Verify the Setup</strong></h1>
<ol>
<li><p><strong>Check DNS Resolution</strong></p>
</li>
<li><p>On the client, verify that DNS resolution works:</p>
</li>
</ol>
<pre><code class="lang-plaintext">ping main.abc.local 
ping branch.abc.local  
nslookup main.abc.local 
nslookup branch.abc.local  
nslookup client.abc.local
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*4nhSSnrCX9vV7Sbc" alt /></p>
<p><strong>External DNS Resolution:</strong></p>
<ul>
<li><code>nslookup google.com</code></li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:980/0*Rxjttw0uWq14RluA" alt /></p>
<ol>
<li><p><strong>Test External DNS Resolution</strong></p>
</li>
<li><p>On the branch server, test that external domain resolution works:</p>
</li>
</ol>
<ul>
<li><code>dig google.com</code></li>
</ul>
<ol>
<li><p><strong>Check BIND9 Status</strong></p>
</li>
<li><p>Ensure that BIND9 is running correctly on both the main and branch servers:</p>
</li>
</ol>
<ul>
<li><code>sudo systemctl status bind9</code></li>
</ul>
<p>By following these steps, you should have a working DNS setup where the branch office can resolve both local and external domains through the main office DNS server.</p>
<h1 id="heading-steps-to-deploy-tinc-vpn"><strong>Steps to Deploy Tinc VPN</strong></h1>
<p><strong>Tinc VPN</strong> is a flexible and powerful VPN daemon that supports full-mesh routing and dynamic links between nodes. Here’s how to deploy Tinc VPN on both the main server and branch server.</p>
<h1 id="heading-prerequisites"><strong>Prerequisites</strong></h1>
<ul>
<li><p>Two Linux servers (main and branch) with root or sudo access.</p>
</li>
<li><p>Ensure that both servers have open network ports for Tinc (default is 655 for TCP and UDP).</p>
</li>
</ul>
<h1 id="heading-step-1-install-tinc-vpn"><strong>Step 1: Install Tinc VPN</strong></h1>
<p><strong>On Both Servers [main and branch]:</strong></p>
<ol>
<li><strong>Update the package list and install Tinc:</strong></li>
</ol>
<ul>
<li><code>sudo apt update sudo apt install tinc</code></li>
</ul>
<h1 id="heading-step-2-create-tinc-configuration-directories"><strong>Step 2: Create Tinc Configuration Directories</strong></h1>
<p><strong>On Both Servers:</strong></p>
<ol>
<li><strong>Create the main configuration directory for Tinc:</strong></li>
</ol>
<ul>
<li><code>sudo mkdir -p /etc/tinc/vpn/hosts</code></li>
</ul>
<ol>
<li><strong>Navigate to the Tinc directory:</strong></li>
</ol>
<ul>
<li><code>cd /etc/tinc/vpn</code></li>
</ul>
<h1 id="heading-step-3-generate-tinc-configuration-files"><strong>Step 3: Generate Tinc Configuration Files</strong></h1>
<p><strong>On Both Servers:</strong></p>
<ol>
<li><strong>Create the</strong><code>tinc.conf</code><strong>file:</strong></li>
</ol>
<ul>
<li><code>sudo nano tinc.conf</code></li>
</ul>
<ol>
<li><p><strong>Add the following configuration (replace</strong><code>MainServer</code><strong>and</strong><code>BranchServer</code><strong>with appropriate hostnames):</strong></p>
</li>
<li><p><strong>Main Server (</strong><code>main</code><strong>):</strong></p>
</li>
</ol>
<pre><code class="lang-plaintext">Name = main  
AddressFamily = ipv4  
Interface = tun0
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:972/0*EDMbic-Bo5VEtbUE" alt /></p>
<ol>
<li><strong>Branch Server (</strong><code>branch</code><strong>):</strong></li>
</ol>
<pre><code class="lang-plaintext">Name = branch  
AddressFamily = ipv4  
Interface = tun0  
ConnectTo = main
</code></pre>
<ol>
<li><strong>Create the</strong><code>tinc-up</code><strong>script:</strong></li>
</ol>
<ul>
<li><code>sudo nano tinc-up</code></li>
</ul>
<ol>
<li><p><strong>Add the following content (adjust IP addresses as needed):</strong></p>
</li>
<li><p><strong>Main Server:</strong></p>
</li>
</ol>
<ul>
<li><code>#!/bin/sh ifconfig $INTERFACE 10.0.0.1 netmask 255.255.255.0</code></li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1035/0*NIeGvXRHYp0dkXps" alt /></p>
<ol>
<li><strong>Branch Server:</strong></li>
</ol>
<ul>
<li><code>#!/bin/sh ifconfig $INTERFACE 10.0.0.2 netmask 255.255.255.0</code></li>
</ul>
<ol>
<li><strong>Make the</strong><code>tinc-up</code><strong>script executable:</strong></li>
</ol>
<ul>
<li><code>sudo chmod +x tinc-up</code></li>
</ul>
<ol>
<li><strong>Create the</strong><code>tinc-down</code><strong>script:</strong></li>
</ol>
<ul>
<li><code>sudo nano tinc-down</code></li>
</ul>
<ol>
<li><strong>Add the following content:</strong></li>
</ol>
<ul>
<li><code>#!/bin/sh ifconfig $INTERFACE down</code></li>
</ul>
<ol>
<li><strong>Make the</strong><code>tinc-down</code><strong>script executable:</strong></li>
</ol>
<ul>
<li><code>sudo chmod +x tinc-down</code></li>
</ul>
<h1 id="heading-step-4-configure-host-files"><strong>Step 4: Configure Host Files</strong></h1>
<p><strong>On Both Servers:</strong></p>
<ol>
<li><p><strong>Create a host configuration file for each server:</strong></p>
</li>
<li><p><strong>Main Server:</strong></p>
</li>
</ol>
<ul>
<li><code>sudo nano hosts/main</code></li>
</ul>
<ol>
<li><strong>Branch Server:</strong></li>
</ol>
<ul>
<li><code>sudo nano hosts/branch</code></li>
</ul>
<ol>
<li><strong>Add the following content:</strong></li>
</ol>
<p><strong>Main Server: [</strong><code>hosts/main]</code></p>
<ul>
<li><code>Address = 192.168.1.10 Subnet = 10.0.0.1/32</code></li>
</ul>
<p><strong>Branch Server: [</strong><code>hosts/branch]</code></p>
<ul>
<li><code>Address = 192.168.5.10 Subnet = 10.0.0.2/32</code></li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*oSyKzZ4PzYpGS5Ti" alt /></p>
<h1 id="heading-step-5-generate-tinc-keys"><strong>Step 5: Generate Tinc Keys</strong></h1>
<p><strong>On Both Servers:</strong></p>
<ol>
<li><strong>Generate the Tinc RSA key pair:</strong></li>
</ol>
<pre><code class="lang-plaintext">sudo tincd -n vpn -K4096
</code></pre>
<p><strong>This will generate</strong><code>rsa_key.priv</code><strong>and</strong><code>hosts/&lt;hostname&gt;</code><strong>files.<br />Share the contents of these files between the servers:</strong></p>
<p><strong>Main Server:</strong></p>
<ul>
<li><code>sudo cat /etc/tinc/vpn/hosts/main</code></li>
</ul>
<p><strong>Branch Server:</strong></p>
<ul>
<li><code>sudo cat /etc/tinc/vpn/hosts/branch</code></li>
</ul>
<ol>
<li><p><strong>Copy the public key portion (the lines starting with</strong><code>-----BEGIN RSA PUBLIC KEY-----</code><strong>to</strong><code>-----END RSA PUBLIC KEY-----</code><strong>) from each server and add it to the corresponding host file on the other server:</strong></p>
</li>
<li><p><strong>On Main Server (</strong><code>/etc/tinc/vpn/hosts/branch</code><strong>):</strong></p>
</li>
</ol>
<ul>
<li><code>-----BEGIN RSA PUBLIC KEY----- (Branch Server public key here) -----END RSA PUBLIC KEY-----</code></li>
</ul>
<ol>
<li><strong>On Branch Server (</strong><code>/etc/tinc/vpn/hosts/main</code><strong>):</strong></li>
</ol>
<ul>
<li><code>-----BEGIN RSA PUBLIC KEY----- (Main Server public key here) -----END RSA PUBLIC KEY-----</code></li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*HVRlhMrUHbp2YGcs" alt /></p>
<ol>
<li>Ensure the hosts files, main and branch exists on both servers. [copy them all to each other]</li>
</ol>
<p><img src="https://miro.medium.com/v2/resize:fit:965/0*vjnzNWI2XHAa8bp5" alt /></p>
<h1 id="heading-step-6-start-tinc-vpn"><strong>Step 6: Start Tinc VPN</strong></h1>
<p><strong>On Both Servers:</strong></p>
<ol>
<li><strong>Enable and start the Tinc service:</strong></li>
</ol>
<ul>
<li><code>sudo systemctl enable tinc@vpn sudo systemctl start tinc@vpn sudo systemctl status tinc@vpn</code></li>
</ul>
<ol>
<li><strong>Check the status of the Tinc service:</strong></li>
</ol>
<ul>
<li><code>sudo systemctl status tinc@vpn</code></li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*Mop_uZKOOQcKYc_u" alt /></p>
<h1 id="heading-step-7-verify-the-connection"><strong>Step 7: Verify the Connection</strong></h1>
<ol>
<li><strong>Verify that the</strong><code>tun0</code><strong>interface is up and configured correctly on both servers:</strong></li>
</ol>
<ul>
<li><code>ifconfig tun0</code></li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*6LjSz0skWBI2bt_d" alt /></p>
<ol>
<li><strong>Check the connectivity between the servers:</strong></li>
</ol>
<ul>
<li><code>ping 10.0.0.2 # From Main Server ping 10.0.0.1 # From Branch Server ssh osboxes@10.0.0.2 # From Main Server ifconfig tun0</code></li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*SuGojfpamd9GgTTB" alt /></p>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*S54Q5jn1JKqb6PHR" alt /></p>
<h1 id="heading-setup-dhcp-on-branch-office"><strong>Setup DHCP on Branch Office:</strong></h1>
<ol>
<li><strong>Install DHCP (isc-dhcp-server):</strong></li>
</ol>
<ul>
<li><code>sudo apt update sudo apt install isc-dhcp-server</code></li>
</ul>
<ol>
<li><p><strong>Configure DHCP Server:</strong></p>
</li>
<li><p>Edit the DHCP server configuration file:</p>
</li>
</ol>
<ul>
<li><code>sudo nano /etc/dhcp/dhcpd.conf</code></li>
</ul>
<ol>
<li>Add or modify the following lines to configure the DHCP server:</li>
</ol>
<pre><code class="lang-plaintext"># Optionally specify a domain name
option domain-name "company.local";

# Specify the default lease time (in seconds)
default-lease-time 600;

# Specify the maximum lease time (in seconds)
max-lease-time 7200;

# Specify the network and subnet
subnet 192.168.5.0 netmask 255.255.255.0 {
    range 192.168.5.50 192.168.5.100;  # IP range to be assigned to clients
    option routers 192.168.5.10;       # Gateway
    option domain-name-servers 192.168.5.10, 8.8.8.8;  # DNS servers
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*zXPcIF-je13G-3Ej" alt /></p>
<ol>
<li><p><strong>Specify Network Interface for DHCP:</strong></p>
</li>
<li><p>Edit the file <code>/etc/default/isc-dhcp-server</code> to specify the network interface that the DHCP server should listen on. For example:</p>
</li>
</ol>
<pre><code class="lang-plaintext">INTERFACESv4="ens33"
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/1*gxDDE1GCo6hsUjfrxN97tg.png" alt /></p>
<p>Replace <code>ens33</code> with the name of the network interface connected to your local network.</p>
<ol>
<li><p><strong>Restart DHCP Server:</strong></p>
</li>
<li><p>Activate and start the DHCP server to apply the changes:</p>
</li>
</ol>
<pre><code class="lang-plaintext">sudo systemctl start isc-dhcp-server
systemctl status isc-dhcp-server
systemctl enable isc-dhcp-server
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*_myWMSdhrMVs2bvS" alt /></p>
<h1 id="heading-on-the-client-server"><strong>On the Client Server</strong></h1>
<h2 id="heading-1-configure-netplan-for-dhcp"><strong>1. Configure Netplan for DHCP</strong></h2>
<p>Edit the Netplan configuration file to use DHCP for obtaining an IP address:</p>
<ol>
<li><strong>Edit Netplan Configuration:</strong></li>
</ol>
<pre><code class="lang-plaintext">sudo nano /etc/netplan/01-netcfg.yaml
</code></pre>
<ol>
<li><p><strong>Modify the Configuration to Use DHCP:</strong></p>
</li>
<li><p>Update the file to use DHCP for the <code>ens33</code> interface:</p>
</li>
</ol>
<pre><code class="lang-plaintext">network:
version: 2
ethernets:
 ens33:
   dhcp4: yes
   routes:
     - to: default
       via: 192.168.5.10
   nameservers:
     addresses:
       - 8.8.8.8
       - 8.8.4.4
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*4-MBbniaYbnrMWbl" alt /></p>
<ol>
<li><strong>Apply the Netplan configuration:</strong></li>
</ol>
<ul>
<li><code>sudo netplan apply</code></li>
</ul>
<ol>
<li>A new network will be created and will then need to be attached to ens33, then reboot so that it can pickup an IP.</li>
</ol>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*aBjTuW5Ihvwqhskv" alt /></p>
<ol>
<li>Or you can use below command to configure the network to be auto assigned an IP.</li>
</ol>
<pre><code class="lang-plaintext">sudo nmcli con add type ethernet ifname ens33 con-name netplan-ens33 ipv4.method auto
</code></pre>
<h1 id="heading-verify-the-setup-1"><strong>Verify the Setup</strong></h1>
<ol>
<li><strong>Check DHCP Lease on Client:</strong></li>
</ol>
<pre><code class="lang-plaintext">nmcli con show 
sudo nmcli con up netplan-ens33 
nmcli device show ens33 
nmcli device status 
nmcli con show netplan-ens33
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*05WC6yVagrcLdjV7" alt /></p>
<p>Once the client server is powered up, it should automatically obtain an IP address from the branch server. Verify the IP address on the client:</p>
<pre><code class="lang-plaintext">ip addr show ens33
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*0HfUgYTE6wOnP2F4" alt /></p>
<p>You should see an IP address within the range specified in the DHCP server configuration (e.g., <code>192.168.5.15</code> to <code>192.168.5.40</code>).</p>
<p>By following these steps, your branch server will act as a DHCP server, and the client server will automatically receive its IP address from the branch server when powered up.</p>
<h1 id="heading-provide-internet-access-from-branch-office-server-to-client-system"><strong>Provide Internet Access from Branch Office Server to Client System</strong></h1>
<p>To provide internet access from your branch office server (which has internet access) to your client system (which does not), you can set up Network Address Translation (NAT) and configure IP forwarding on the branch office server. Here’s a step-by-step guide to achieve this on your Ubuntu server:</p>
<h1 id="heading-1-enable-ip-forwarding"><strong>1. Enable IP Forwarding</strong></h1>
<p>You need to enable IP forwarding on the branch office server to allow it to forward packets between the client system and the internet.</p>
<p>Open the <code>/etc/sysctl.conf</code> file with a text editor:</p>
<pre><code class="lang-plaintext">sudo nano /etc/sysctl.conf
</code></pre>
<p>Find the line:</p>
<pre><code class="lang-plaintext">#net.ipv4.ip_forward=1
</code></pre>
<p>Uncomment it (remove the <code>#</code>), so it reads:</p>
<pre><code class="lang-plaintext">net.ipv4.ip_forward=1
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*gYJIuuwr44s4Z1K4" alt /></p>
<p>Apply the changes:</p>
<pre><code class="lang-plaintext">sudo sysctl -p
</code></pre>
<h1 id="heading-2-configure-nat-network-address-translation"><strong>2. Configure NAT (Network Address Translation)</strong></h1>
<p>Use <code>iptables</code> to configure NAT on the branch office server. This will allow the client system to use the branch office server’s internet connection.</p>
<p>Run the following commands:</p>
<pre><code class="lang-plaintext">sudo iptables -t nat -A POSTROUTING -o ens38 -j MASQUERADE
sudo iptables -A FORWARD -i ens38 -o ens33 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i ens33 -o ens38 -j ACCEPT
</code></pre>
<p>Replace <code>&lt;internet_interface&gt;</code> with the name of the network interface connected to the internet (e.g., <code>ens33</code>) and <code>&lt;client_interface&gt;</code> with the name of the network interface [<code>BranchOfficeNet]</code>connected to the client system (e.g., <code>ens34</code>).</p>
<h1 id="heading-3-save-theiptables-configuration"><strong>3. Save the</strong><code>iptables</code> Configuration</h1>
<p>To ensure that your <code>iptables</code> rules persist after a reboot, you need to save them. On Ubuntu, you can use the <code>iptables-save</code> command and store the rules in a file.</p>
<p>Save the rules:</p>
<p>Install <code>iptables-persistent</code> to load the rules at boot [if not already installed]:</p>
<pre><code class="lang-plaintext">sudo apt-get install iptables-persistent
</code></pre>
<pre><code class="lang-plaintext">sudo sh -c "iptables-save &gt; /etc/iptables/rules.v4"
OR
sudo iptables-save | sudo tee /etc/iptables/rules.v4
</code></pre>
<p>Check that the NAT rule is in place:</p>
<pre><code class="lang-plaintext">sudo iptables -t nat -L -v
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*xzy8yV5690msKEoy" alt /></p>
<h1 id="heading-4-configure-the-client-system"><strong>4. Configure the Client System</strong></h1>
<p>Ensure that the client system has its default gateway set to the branch office server’s IP address on the local network.</p>
<p>On the client system, you can set the default gateway by editing the <code>/etc/netplan/01-netcfg.yaml</code> file or using the <code>ip route</code> command. For example:</p>
<p>sudo nano /etc/netplan/01-netcfg.yaml<br />network:<br />version: 2<br />ethernets: ens33:<br />dhcp4: yes<br />routes:</p>
<pre><code class="lang-plaintext">network:
  version: 2
  ethernets:
    ens33:
      dhcp4: yes
      routes:
        - to: default
          via: 192.168.5.10
      nameservers:
        addresses:
          - 192.168.5.10
          - 8.8.8.8
</code></pre>
<pre><code class="lang-plaintext">sudo netplan apply
</code></pre>
<h1 id="heading-5-test-the-configuration"><strong>5. Test the Configuration</strong></h1>
<p>Test the internet connectivity from the client system by pinging an external website or using a web browser.</p>
<pre><code class="lang-plaintext">ping google.com
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*CmpbknY4PSSxIoUS" alt /></p>
<h1 id="heading-ntp-setup"><strong>NTP setup</strong></h1>
<p>I will be using <code>chrony</code> set up the NTP service, where the client system receives time sychronization from the branch server, following these steps:</p>
<h1 id="heading-on-the-branch-server"><strong>On the Branch Server</strong></h1>
<ol>
<li><strong>Install Chrony:</strong></li>
</ol>
<pre><code class="lang-plaintext">sudo apt-get update
sudo apt-get install chrony -y
</code></pre>
<ol>
<li><strong>Configure Chrony:</strong></li>
</ol>
<p>Edit the Chrony configuration file:</p>
<pre><code class="lang-plaintext">sudo nano /etc/chrony/chrony.conf
</code></pre>
<p>Add the following lines to allow the client server to get time from the branch server:</p>
<pre><code class="lang-plaintext">allow 192.168.5.0/24
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*l0AKCXg7PMw26qao" alt /></p>
<p>This <code>allow</code> directive permits the specified network to access the time service. Adjust the network range if necessary.</p>
<p>Configure IPtables to permit NTP service syncronization on port 123 from client systems:</p>
<pre><code class="lang-plaintext">sudo iptables -A INPUT -p udp --dport 123 -j ACCEPT
sudo iptables -A OUTPUT -p udp --sport 123 -j ACCEPT
</code></pre>
<pre><code class="lang-plaintext">sudo iptables-save | sudo tee /etc/iptables/rules.v4
sudo iptables -L -v -n
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*t-SBCbqYBgFQRnF8" alt /></p>
<ol>
<li><strong>Start Chrony:</strong></li>
</ol>
<pre><code class="lang-plaintext">sudo systemctl start chrony
sudo systemctl enable chrony
</code></pre>
<ol>
<li><strong>Verify Chrony Status:</strong></li>
</ol>
<pre><code class="lang-plaintext">sudo systemctl status chrony
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*55DD3VZTWN77c8TY" alt /></p>
<h1 id="heading-on-the-client-server-1"><strong>On the Client Server</strong></h1>
<ol>
<li><strong>Install Chrony:</strong></li>
</ol>
<pre><code class="lang-plaintext">sudo apt-get update
sudo apt-get install chrony -y
</code></pre>
<ol>
<li><strong>Configure Chrony:</strong></li>
</ol>
<p>Edit the Chrony configuration file:</p>
<pre><code class="lang-plaintext">sudo nano /etc/chrony/chrony.conf
</code></pre>
<p>Add the branch server’s IP address as the NTP server, remove all other default ntp sources by hashing it out:</p>
<pre><code class="lang-plaintext">server 192.168.5.10 iburst #Branch server IP address
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*l0VNfAhWJmeElNbt" alt /></p>
<ol>
<li><strong>Start Chrony:</strong></li>
</ol>
<pre><code class="lang-plaintext">sudo systemctl start chrony
</code></pre>
<ol>
<li><strong>Verify Chrony Status:</strong></li>
</ol>
<pre><code class="lang-plaintext">sudo systemctl status chrony
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*E_WlcLxsFuf03qL9" alt /></p>
<h1 id="heading-verification"><strong>Verification</strong></h1>
<p>On the brannch server, run ‘netplan apply’</p>
<p>To ensure that the client server is correctly synchronizing its time from the branch server, you can use the <code>chronyc</code> command.</p>
<p><strong>On the Client Server:</strong></p>
<ol>
<li><strong>Check Chrony Sources:</strong></li>
</ol>
<pre><code class="lang-plaintext">chronyc sources
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*UE5XhqQYRu9fXXxh" alt /></p>
<p>You should see the branch server (<code>192.168.5.10</code> or its <code>hostname</code>) listed as a source.</p>
<ol>
<li><strong>Other chrony commands are listed below:</strong></li>
</ol>
<pre><code class="lang-plaintext">chronyc tracking
sudo chronyc -a makestep
chronyc activity
chronyc serverstats
chronyc sources -v
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*4zhR_Yz4C8damUDT" alt /></p>
<h1 id="heading-to-set-up-snort-to-monitor-for-suspicious-activity-on-your-servers-follow-these-steps"><strong>To set up Snort to monitor for suspicious activity on your servers, follow these steps:</strong></h1>
<h1 id="heading-1-install-snort"><strong>1. Install Snort</strong></h1>
<h2 id="heading-on-debianubuntu"><strong>On Debian/Ubuntu:</strong></h2>
<pre><code class="lang-plaintext">sudo apt update
sudo apt install snort
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*tQEfO68RFSy1RGHO" alt /></p>
<h1 id="heading-2-configure-snort"><strong>2. Configure Snort</strong></h1>
<h2 id="heading-initial-configuration"><strong>Initial Configuration:</strong></h2>
<p>Snort’s main configuration file is located at <code>/etc/snort/snort.conf</code>. Open this file to configure it according to your network setup.</p>
<pre><code class="lang-plaintext">sudo nano /etc/snort/snort.conf
</code></pre>
<h2 id="heading-configure-network-variables"><strong>Configure Network Variables:</strong></h2>
<p>Set your HOME_NET and EXTERNAL_NET variables. set up Snort to monitor three interfaces with different subnet, set it as follows:</p>
<p>for Main server:</p>
<pre><code class="lang-plaintext">var HOME_NET [192.168.1.0/24,10.0.0.0/24,192.168.79.0/24]
var EXTERNAL_NET !$HOME_NET
</code></pre>
<p>for branch server:</p>
<pre><code class="lang-plaintext">var HOME_NET [192.168.5.0/24,10.0.0.0/24,192.168.79.0/24] 
var EXTERNAL_NET !$HOME_NET
</code></pre>
<p>for client:</p>
<pre><code class="lang-plaintext">var HOME_NET 192.168.5.0/24 
var EXTERNAL_NET !$HOME_NET
</code></pre>
<h2 id="heading-include-rule-files"><strong>Include Rule Files:</strong></h2>
<p>Ensure the rule paths are correctly specified:</p>
<pre><code class="lang-plaintext">echo 'include $RULE_PATH/local.rules' &gt;&gt; /etc/snort/snort.conf
</code></pre>
<h1 id="heading-4-create-local-rules"><strong>4. Create Local Rules</strong></h1>
<p>You can create custom rules specific to your network in the <code>local.rules</code> file:</p>
<pre><code class="lang-plaintext">sudo nano /etc/snort/rules/local.rules
</code></pre>
<p>Add some basic rules:</p>
<pre><code class="lang-plaintext"># Alert on any ICMP traffic
alert icmp any any -&gt; any any (msg:"ICMP Traffic Detected"; sid:1000001; rev:1;)

# Alert on any TCP traffic to port 123 (NTP)
alert tcp any any -&gt; any 123 (msg:"TCP Traffic to NTP port 123 detected"; sid:1000002; rev:1;)

# Alert on any TCP traffic to port 53 (DNS)
alert tcp any any -&gt; any 53 (msg:"TCP Traffic to DNS port 53 detected"; sid:1000003; rev:1;)

# Alert on any UDP traffic to port 53 (DNS)
alert udp any any -&gt; any 53 (msg:"UDP Traffic to DNS port 53 detected"; sid:1000004; rev:1;)

# Alert on any TCP traffic to port 22 (SSH)
alert tcp any any -&gt; any 22 (msg:"TCP Traffic to SSH port 22 detected"; sid:1000005; rev:1;)
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*ACmLBRRfL2N5oIFp" alt /></p>
<h1 id="heading-5-test-snort-configuration"><strong>5. Test Snort Configuration</strong></h1>
<p>Test the configuration to ensure there are no syntax errors:</p>
<pre><code class="lang-plaintext">sudo snort -T -c /etc/snort/snort.conf
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*0r_JxSzT_7_uhV58" alt /></p>
<h1 id="heading-6-run-snort"><strong>6. Run Snort</strong></h1>
<p>Run Snort in IDS mode:</p>
<p>To monitor multiple network interfaces with Snort, You can run Snort multiple times, each time specifying a different interface:</p>
<pre><code class="lang-plaintext">snort -A console -c /etc/snort/snort.conf -i &lt;network-interface&gt;
snort -A console -c /etc/snort/snort.conf -i ens33 &amp;
snort -A console -c /etc/snort/snort.conf -i eth1 &amp;
</code></pre>
<p>Replace <code>&lt;network-interface&gt;</code> with your network interface, for example, <code>ens33</code>.</p>
<ul>
<li>Sample output of result</li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*V-UyifKOLrVN7I0Y" alt /></p>
<h1 id="heading-7-automate-snort-startup"><strong>7. Automate Snort Startup</strong></h1>
<p>To ensure Snort starts on boot, create a systemd service file.</p>
<h2 id="heading-create-systemd-service-file"><strong>Create Systemd Service File:</strong></h2>
<pre><code class="lang-plaintext">sudo nano /etc/systemd/system/snort33.service
</code></pre>
<p>Add the following content:</p>
<pre><code class="lang-plaintext">[Unit]
Description=Snort NIDS
After=network.target

[Service]
ExecStart=/usr/sbin/snort -c /etc/snort/snort.conf -i ens33
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
</code></pre>
<h2 id="heading-create-another-systemd-service-file-for-vpn-tunnel-connecting-branch-and-main-servers"><strong>Create another Systemd Service File for vpn tunnel [connecting branch and main servers]:</strong></h2>
<pre><code class="lang-plaintext">sudo nano /etc/systemd/system/tun.service
</code></pre>
<p>Add the following content:</p>
<pre><code class="lang-plaintext">[Unit]
Description=Snort tunnel NIDS
After=network.target

[Service]
ExecStart=/usr/sbin/snort -c /etc/snort/snort.conf -i tun0
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
</code></pre>
<h2 id="heading-start-the-services"><strong>Start the services</strong></h2>
<pre><code class="lang-plaintext">systemctl daemon-reload
systemctl enable tun.service
systemctl start tun.service
</code></pre>
<pre><code class="lang-plaintext">systemctl enable snort33.service
systemctl start snort33.service
systemctl status snort33.service
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*xfIDMPW2EgLfB4I7" alt /></p>
<h1 id="heading-8-monitor-snort-logs"><strong>8. Monitor Snort Logs</strong></h1>
<p>Snort logs its alerts to <code>/var/log/snort/snort.alert.fast</code> by default. You can monitor this file for suspicious activity.</p>
<pre><code class="lang-plaintext">tail -f /var/log/snort/snort.alert.fast
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*Y0Xe-30UVExmm9Op" alt /></p>
<p>By following these steps, Snort will monitor your network traffic for suspicious activity and log alerts based on the rules defined. You can optionally adjust and expand the rules and configuration to match the specific requirements and threats relevant to your environment.</p>
<h1 id="heading-configure-nmap"><strong>Configure NMAP:</strong></h1>
<p>To use <code>nmap</code> for network scanning and to ensure that all expected services are running and accessible, follow these steps:</p>
<h1 id="heading-1-install-nmap-on-branch-server"><strong>1. Install Nmap on branch server</strong></h1>
<p>First, make sure <code>nmap</code> is installed on your system. You can install it using the package manager for your distribution:</p>
<p>For Debian/Ubuntu-based systems:</p>
<pre><code class="lang-plaintext">sudo apt-get update
sudo apt-get install nmap
</code></pre>
<h1 id="heading-2-basic-network-scan"><strong>2. Basic Network Scan</strong></h1>
<p>To scan an entire network for live hosts and open ports, use:</p>
<pre><code class="lang-plaintext">nmap -sP 192.168.5.0/24
</code></pre>
<p>or</p>
<pre><code class="lang-plaintext">nmap -sn 192.168.5.0/24
</code></pre>
<p>This will perform a “ping scan” to determine which hosts are online.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*04_Ahr4cxfK65WP8" alt /></p>
<h1 id="heading-3-service-detection"><strong>3. Service Detection</strong></h1>
<p>To detect services running on specific hosts or an entire network, use the following command:</p>
<pre><code class="lang-plaintext">nmap -sV 192.168.5.0/24
</code></pre>
<p>This performs a service/version detection scan to determine what services and versions are running on open ports.</p>
<h1 id="heading-4-port-scanning"><strong>4. Port Scanning</strong></h1>
<p>To scan for open ports on a specific host:</p>
<pre><code class="lang-plaintext">nmap -p- 192.168.5.10
</code></pre>
<p>This scans all 65535 ports. You can specify a range of ports:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*41APSr5YOzTJiVrT" alt /></p>
<p>Command below scans for port 22 and port 80 on the server</p>
<pre><code class="lang-plaintext">nmap -p 22,80,443 192.168.5.15
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*HRr0f19CEA8ocpxw" alt /></p>
<h1 id="heading-5-aggressive-scan"><strong>5. Aggressive Scan</strong></h1>
<p>An aggressive scan performs a detailed scan including service detection, OS detection, and more:</p>
<pre><code class="lang-bash">nmap -A 192.168.5.15
</code></pre>
<p>This will give you extensive information about the host, including open ports, services, OS, and more.</p>
<h1 id="heading-7-scan-multiple-hosts"><strong>7. Scan Multiple Hosts</strong></h1>
<p>To scan multiple hosts or subnets, list them in the command:</p>
<pre><code class="lang-plaintext">sudo nmap -p 80,22 192.168.5.10 192.168.5.15 192.168.1.10
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*mWI9sKBu9O0wMNr6" alt /></p>
<h1 id="heading-8-output-formats"><strong>8. Output Formats</strong></h1>
<p>For easier analysis, you can save the results in various formats:</p>
<ul>
<li><strong>Normal Output</strong>:</li>
</ul>
<pre><code class="lang-plaintext">sudo nmap -oN scan_results.txt 192.168.5.15 192.168.5.10
</code></pre>
<h1 id="heading-9-schedule-regular-scans"><strong>9. Schedule Regular Scans</strong></h1>
<p>To ensure services are consistently monitored, you can set up a cron job to run <code>nmap</code> regularly.</p>
<p>Edit the crontab with:</p>
<pre><code class="lang-plaintext">crontab -e
</code></pre>
<p>Add an entry to run <code>nmap</code> at a regular interval, e.g., daily at midnight:</p>
<pre><code class="lang-plaintext">0 0 * * * /usr/bin/nmap -sP 192.168.5.0/24 &gt; /var/log/nmap_daily_scan.log
</code></pre>
<p>These steps will help ensure all expected services are running and accessible on your network.</p>
<h1 id="heading-capture-network-packets-withtcpdump"><strong>Capture network packets with</strong><code>tcpdump</code></h1>
<p>Capturing and analyzing network traffic using <code>tcpdump</code> and <code>Wireshark</code> can help you verify that your VPN is working correctly and identify any potential issues. Below are the steps to perform this task on both the main and branch servers.</p>
<h2 id="heading-installtcpdump-if-not-already-pre-installed"><strong>Install</strong><code>tcpdump</code> if not already pre-installed.</h2>
<p>For Debian/Ubuntu-based systems:</p>
<pre><code class="lang-plaintext">sudo apt-get update
sudo apt-get install tcpdump
</code></pre>
<h2 id="heading-capture-traffic"><strong>Capture Traffic</strong></h2>
<p>You need to capture traffic on the interfaces involved in the VPN connection. For example, my VPN setup interface is <code>tun0</code>, I can use the following command:</p>
<pre><code class="lang-plaintext">sudo tcpdump -i tun0 -w vpn_traffic.pcap
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*SPXavKeprKPuOy5y" alt /></p>
<ul>
<li><p><code>-i tun0</code>: Specifies the interface to capture traffic on (replace <code>tun0</code> with your own actual VPN interface).</p>
</li>
<li><p><code>-w vpn_traffic.pcap</code>: Writes the captured packets to a file named <code>vpn_traffic.pcap</code>.</p>
</li>
</ul>
<p>You can also filter the traffic by IP address or port if you want to narrow down the capture:</p>
<pre><code class="lang-plaintext">sudo tcpdump -i tun0 host 10.0.0.1 -w vpn_traffic.pcap
</code></pre>
<h2 id="heading-capture-on-both-servers"><strong>Capture on Both Servers</strong></h2>
<p>Run the above <code>tcpdump</code> commands on both the main and branch servers to capture the relevant traffic.</p>
<p>I will also run a ping and ssh commands across both servers in another session so that ICMP and SSH packets can be captured in the tcpdump process.</p>
<pre><code class="lang-plaintext">ping 10.0.0.2 # From the main server 
ping 10.0.0.1 # From the branch server 
ssh user@10.0.0.2 # From the main server 
ssh user@10.0.0.1 # From the branch server
</code></pre>
<h1 id="heading-step-2-transfer-the-capture-files"><strong>Step 2: Transfer the Capture Files</strong></h1>
<p>After capturing the traffic, transfer the <code>.pcap</code> files to your local machine for analysis. You can use <code>scp</code> (secure copy) to do this:</p>
<pre><code class="lang-plaintext">scp user@branch_server:/path/to/vpn_traffic.pcap /local/path/
scp user@main_server:/path/to/vpn_traffic.pcap /local/path/
</code></pre>
<h1 id="heading-step-3-analyze-traffic-with-wireshark"><strong>Step 3: Analyze Traffic with Wireshark</strong></h1>
<h2 id="heading-install-wireshark"><strong>Install Wireshark</strong></h2>
<p>Wireshark is available for Windows, macOS, and Linux. You can download it from the official <a target="_blank" href="https://www.wireshark.org/">Wireshark website</a>.</p>
<p><strong>Open captured files in Wireshark and analyze:</strong></p>
<ol>
<li><p>Open Wireshark.</p>
</li>
<li><p>Click <code>File -&gt; Open</code> and select the transferred .pcap files to open.</p>
</li>
<li><p>Use Wireshark’s display filters to focus on specific traffic. For example, to display only traffic between two IP addresses, enter below strings in the search bar display fileter, and click on the blue arrow to the right to apply.</p>
</li>
</ol>
<ul>
<li><code>ip.addr == 10.0.0.1 &amp;&amp; ip.addr == 10.0.0.2</code></li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*hmNfweAixCH0OB9m" alt /></p>
<p><strong>4. Inspect VPN Traffic</strong>: Look at the traffic on the <code>tun0</code> interface (or your VPN interface) to ensure packets are being transmitted and received correctly.</p>
<p><strong>5. Check for Anomalies</strong>: Look for retransmissions, malformed packets, or any other unusual activity.</p>
<p>By following these steps, you can capture and analyze the network traffic on both your main and branch servers, verify the VPN functionality, and troubleshoot any potential issues using <code>tcpdump</code> and Wireshark.</p>
<h1 id="heading-automation"><strong>AUTOMATION</strong></h1>
<h1 id="heading-configure-ansible-playbooks"><strong>Configure Ansible Playbooks</strong></h1>
<p>I will also install ansible and Based on the manual steps I have used to initially setup the configuration, I will create Ansible playbooks to automate the setup for DHCP, DNS, NTP, and basic firewall rules.</p>
<p>Here is a code file containing the steps to install and configure Ansible on an Ubuntu system for this environment.</p>
<pre><code class="lang-plaintext">#!/bin/bash

# Update package index
echo "Updating package index..."
sudo apt update

# Install Ansible
echo "Installing Ansible..."
sudo apt install ansible -y

# Optionally, install the latest version of Ansible via PPA
echo "Adding Ansible PPA..."
sudo add-apt-repository ppa:ansible/ansible -y
sudo apt update
sudo apt install ansible -y

# Verify Ansible installation
echo "Verifying Ansible installation..."
ansible --version

# Create and configure the inventory file
echo "Configuring Ansible inventory file..."
sudo tee /etc/ansible/hosts &gt; /dev/null &lt;&lt;EOL
[main_server]
192.168.1.10

[branch_server]
192.168.5.10

[client_server]
192.168.5.15
EOL

# Edit the Ansible configuration file
echo "Editing Ansible configuration file..."
sudo tee /etc/ansible/ansible.cfg &gt; /dev/null &lt;&lt;EOL
[defaults]
inventory = /etc/ansible/hosts
remote_user = your_user
private_key_file = /path/to/private/key
EOL

# Test Ansible configuration
echo "Testing Ansible configuration..."
ansible all -m ping

echo "Ansible installation and configuration complete!"
</code></pre>
<h1 id="heading-instructions-for-using-the-script"><strong>Instructions for Using the Script</strong></h1>
<p><strong>Save the Script:</strong></p>
<p>Save the above script to a file, e.g., <code>install_ansible.sh</code>.</p>
<p><strong>Make the Script Executable:</strong></p>
<pre><code class="lang-plaintext">chmod +x install_ansible.sh
</code></pre>
<p><strong>Run the Script:</strong></p>
<pre><code class="lang-plaintext">./install_ansible.sh
</code></pre>
<p>This script handles the installation of Ansible, adds the Ansible PPA if desired, sets up the inventory file, and configures the Ansible configuration file. Adjust the <code>remote_user</code> and <code>private_key_file</code> in the Ansible configuration file according to your setup.</p>
<p>Below are the Ansible playbooks for each service:</p>
<h1 id="heading-1-dhcp-configuration"><strong>1. DHCP Configuration</strong></h1>
<p><strong>Playbook:</strong><code>dhcp.yml</code></p>
<pre><code class="lang-plaintext">---
- name: Configure DHCP Server
  hosts: branch_server
  become: yes
  tasks:
    - name: Install DHCP server
      apt:
        name: isc-dhcp-server
        state: present
        update_cache: yes

    - name: Configure DHCP server
      copy:
        dest: /etc/dhcp/dhcpd.conf
        content: |
          option domain-name "company.local";
          default-lease-time 600;
          max-lease-time 7200;

          subnet 192.168.5.0 netmask 255.255.255.0 {
              range 192.168.5.50 192.168.5.100;
              option routers 192.168.5.10;
              option domain-name-servers 192.168.5.10, 8.8.8.8;
          }

    - name: Specify network interface for DHCP
      lineinfile:
        path: /etc/default/isc-dhcp-server
        regexp: '^INTERFACESv4='
        line: 'INTERFACESv4="ens33"'

    - name: Restart DHCP server
      service:
        name: isc-dhcp-server
        state: restarted
        enabled: yes
</code></pre>
<h1 id="heading-2-dns-configuration"><strong>2. DNS Configuration</strong></h1>
<p><strong>Playbook:</strong><code>dns.yml</code></p>
<pre><code class="lang-plaintext">---
- name: Configure DNS Server
  hosts: main_server
  become: yes
  tasks:
    - name: Install BIND9
      apt:
        name: "{{ item }}"
        state: present
        update_cache: yes
      with_items:
        - bind9
        - bind9utils
        - bind9-doc

    - name: Configure BIND9 named.conf.local
      copy:
        dest: /etc/bind/named.conf.local
        content: |
          zone "abc.local" {
              type master;
              file "/etc/bind/db.abc.local";
          };

          zone "5.168.192.in-addr.arpa" {
              type master;
              file "/etc/bind/db.192.168.5";
          };

    - name: Create forward zone file for abc.local
      copy:
        dest: /etc/bind/db.abc.local
        content: |
          $TTL    604800
          @       IN      SOA     main.abc.local. admin.abc.local. (
                                   2         ; Serial
                              604800         ; Refresh
                               86400         ; Retry
                             2419200         ; Expire
                              604800 )       ; Negative Cache TTL
          ;
          @       IN      NS      main.abc.local.
          main    IN      A       192.168.1.10
          branch  IN      A       192.168.5.10
          client  IN      A       192.168.5.15

    - name: Create reverse zone file for 192.168.5.x
      copy:
        dest: /etc/bind/db.192.168.5
        content: |
          $TTL    604800
          @       IN      SOA     main.abc.local. admin.abc.local. (
                                   2         ; Serial
                              604800         ; Refresh
                               86400         ; Retry
                             2419200         ; Expire
                              604800 )       ; Negative Cache TTL
          ;
          @       IN      NS      main.abc.local.
          10      IN      PTR     branch.abc.local.
          15      IN      PTR     client.abc.local.

    - name: Configure BIND9 forwarders
      lineinfile:
        path: /etc/bind/named.conf.options
        insertafter: '{'
        line: |
          forwarders {
              8.8.8.8;  // Google's DNS
              8.8.4.4;  // Google's DNS
          };

    - name: Restart BIND9
      service:
        name: bind9
        state: restarted
        enabled: yes

- name: Configure DNS Server
  hosts: branch_server
  become: yes
  tasks:
    - name: Install BIND9
      apt:
        name: "{{ item }}"
        state: present
        update_cache: yes
      with_items:
        - bind9
        - bind9utils
        - bind9-doc

    - name: Configure BIND9 named.conf.local as slave
      copy:
        dest: /etc/bind/named.conf.local
        content: |
          zone "abc.local" {
              type slave;
              file "/var/cache/bind/db.abc.local";
              masters { 192.168.1.10; };
          };

          zone "5.168.192.in-addr.arpa" {
              type slave;
              file "/var/cache/bind/db.192.168.5";
              masters { 192.168.1.10; };
          };

    - name: Configure BIND9 forwarders
      lineinfile:
        path: /etc/bind/named.conf.options
        insertafter: '{'
        line: |
          forwarders {
              192.168.1.10;  // Main server's IP
          };

    - name: Restart BIND9
      service:
        name: bind9
        state: restarted
        enabled: yes
</code></pre>
<h1 id="heading-3-ntp-configuration-using-chrony-with-iptables-rules"><strong>3. NTP Configuration (using chrony) with iptables rules</strong></h1>
<p><strong>Playbook:</strong><code>ntp.yml</code></p>
<pre><code class="lang-plaintext">---
- name: Configure NTP with Chrony
  hosts: branch_server
  become: yes
  tasks:
    - name: Install chrony
      apt:
        name: chrony
        state: present
        update_cache: yes

    - name: Configure chrony to allow network
      lineinfile:
        path: /etc/chrony/chrony.conf
        line: 'allow 192.168.5.0/24'
        state: present

    - name: Restart chrony
      service:
        name: chrony
        state: restarted
        enabled: yes

    - name: Add iptables rules for chrony
      iptables:
        chain: INPUT
        protocol: udp
        destination_port: 123
        jump: ACCEPT

    - name: Add iptables rules for chrony output
      iptables:
        chain: OUTPUT
        protocol: udp
        source_port: 123
        jump: ACCEPT

    - name: Save iptables rules
      command: iptables-save &gt; /etc/iptables/rules.v4

- name: Configure NTP with Chrony on Client Server
  hosts: client_server
  become: yes
  tasks:
    - name: Install chrony
      apt:
        name: chrony
        state: present
        update_cache: yes

    - name: Configure chrony to use branch server
      lineinfile:
        path: /etc/chrony/chrony.conf
        line: 'server 192.168.5.10 iburst'
        state: present

    - name: Restart chrony
      service:
        name: chrony
        state: restarted
        enabled: yes

    - name: Add iptables rules for chrony
      iptables:
        chain: INPUT
        protocol: udp
        destination_port: 123
        jump: ACCEPT

    - name: Add iptables rules for chrony output
      iptables:
        chain: OUTPUT
        protocol: udp
        source_port: 123
        jump: ACCEPT

    - name: Save iptables rules
      command: iptables-save &gt; /etc/iptables/rules.v4
</code></pre>
<h1 id="heading-4-basic-firewall-rules-with-additional-iptables-rules"><strong>4. Basic Firewall Rules with additional iptables rules</strong></h1>
<p><strong>Playbook:</strong><code>firewall.yml</code></p>
<pre><code class="lang-plaintext">---
- name: Configure basic firewall rules and iptables
  hosts: branch_server
  become: yes
  tasks:
    - name: Install UFW
      apt:
        name: ufw
        state: present
        update_cache: yes

    - name: Allow SSH
      ufw:
        rule: allow
        name: 'OpenSSH'

    - name: Allow DHCP
      ufw:
        rule: allow
        port: 67
        proto: udp

    - name: Allow DNS
      ufw:
        rule: allow
        port: 53
        proto: udp

    - name: Allow NTP
      ufw:
        rule: allow
        port: 123
        proto: udp

    - name: Enable UFW
      ufw:
        state: enabled

    - name: Add NAT iptables rule
      iptables:
        chain: POSTROUTING
        table: nat
        out_interface: ens38
        jump: MASQUERADE

    - name: Add forward rule for related/established connections
      iptables:
        chain: FORWARD
        in_interface: ens38
        out_interface: ens33
        match: state
        state: RELATED,ESTABLISHED
        jump: ACCEPT

    - name: Add forward rule to allow traffic from ens33 to ens38
      iptables:
        chain: FORWARD
        in_interface: ens33
        out_interface: ens38
        jump: ACCEPT

    - name: Save iptables rules
      command: iptables-save &gt; /etc/iptables/rules.v4
</code></pre>
<pre><code class="lang-plaintext">Inventory host File
[main_server]
192.168.1.10[branch_server]
192.168.5.10[client_server]
192.168.5.15[all]
192.168.1.10
192.168.5.10
192.168.5.15
</code></pre>
<h1 id="heading-run-the-playbooks"><strong>Run the Playbooks</strong></h1>
<p>To execute the playbooks, use the following commands:</p>
<pre><code class="lang-plaintext">ansible-playbook -i hosts dhcp.yml
ansible-playbook -i hosts dns.yml
ansible-playbook -i hosts ntp.yml
ansible-playbook -i hosts firewall.yml
</code></pre>
<p>These playbooks will automate the configuration of DHCP, DNS, NTP with iptables rules, and basic firewall rules on the specified servers.</p>
<h1 id="heading-infrastructure-as-code"><strong>Infrastructure as code:</strong></h1>
<p>To use Vagrant to provision a VM on VMware Workstation, simulating an additional branch server and client system, follow these steps. This guide will cover installing the necessary tools, setting up Vagrant, and creating Vagrantfiles to provision the VMs.</p>
<h1 id="heading-prerequisites-1"><strong>Prerequisites</strong></h1>
<ol>
<li><p><strong>VMware Workstation</strong>: Ensure VMware Workstation is installed.</p>
</li>
<li><p><strong>Vagrant</strong>: Install Vagrant on your system. <a target="_blank" href="https://developer.hashicorp.com/vagrant/install">https://developer.hashicorp.com/vagrant/install</a></p>
</li>
<li><p><strong>Vagrant VMware Utility</strong>: Install the Vagrant VMware Utility. <a target="_blank" href="https://developer.hashicorp.com/vagrant/docs/providers/vmware/vagrant-vmware-utility">https://developer.hashicorp.com/vagrant/docs/providers/vmware/vagrant-vmware-utility</a></p>
</li>
<li><p><strong>Vagrant VMware Desktop Plugin</strong>: Install the Vagrant VMware Desktop plugin.</p>
</li>
<li><p>Run the following command in your terminal :</p>
</li>
</ol>
<p><code>vagrant plugin install vagrant-vmware-desktop</code></p>
<h1 id="heading-steps-to-provision-vms-with-vagrant"><strong>Steps to Provision VMs with Vagrant</strong></h1>
<h2 id="heading-1-create-a-directory-for-your-vagrant-project"><strong>1. Create a Directory for Your Vagrant Project</strong></h2>
<p>Create a directory for your Vagrant project, and navigate into it:</p>
<pre><code class="lang-plaintext">mkdir vagrant
cd vagrant
</code></pre>
<h2 id="heading-2-initialize-vagrant"><strong>2. Initialize Vagrant</strong></h2>
<p>Initialize Vagrant in the directory:</p>
<pre><code class="lang-plaintext">vagrant init
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/1*oAVt5HTB1l79kOdl6fqVwQ.png" alt /></p>
<p>This will create a <code>Vagrantfile</code> in the directory. You will modify the <code>Vagrantfile</code>s to contain the resource creation for the 3 VMs. Check for latest OS version at <a target="_blank" href="https://app.vagrantup.com/generic">https://app.vagrantup.com/generic</a></p>
<p>To add additional configurations to each of the VMs, you can use a shell provisioner in the Vagrantfile. Below, I’ve created a script to set up DHCP, iptables, DNS, Chrony, and firewall rules. The script will be called provision.sh, and it will be referenced in the Vagrantfile for each VM.</p>
<pre><code class="lang-plaintext">Vagrant.configure("2") do |config|
  # Define the "main" VM
  config.vm.define "main" do |main|
    main.vm.box = "generic/ubuntu2310"
    main.vm.network "private_network", ip: "192.168.1.10"
    main.vm.hostname = "main"

    main.vm.provider "vmware_desktop" do |v|
      v.vmx["memsize"] = "2048"
      v.vmx["numvcpus"] = "2"
      v.vmx["disk.size"] = "20000"
    end

    main.vm.provision "shell", path: "C:/Users/balog/Desktop/vagrant-branch-client/provision.sh"
  end

  # Define the "branch" VM
  config.vm.define "branch" do |branch|
    branch.vm.box = "generic/ubuntu2310"
    branch.vm.network "private_network", ip: "192.168.5.10"
    branch.vm.hostname = "branch"

    branch.vm.provider "vmware_desktop" do |v|
      v.vmx["memsize"] = "2048"
      v.vmx["numvcpus"] = "2"
      v.vmx["disk.size"] = "20000"
    end

    branch.vm.provision "shell", path: "C:/Users/balog/Desktop/vagrant-branch-client/provision.sh"
  end

  # Define the "client" VM
  config.vm.define "client" do |client|
    client.vm.box = "generic/ubuntu2310"
    client.vm.network "private_network", type: "dhcp"
    client.vm.hostname = "client"

    client.vm.provider "vmware_desktop" do |v|
      v.vmx["memsize"] = "2048"
      v.vmx["numvcpus"] = "2"
      v.vmx["disk.size"] = "20000"
    end

    client.vm.provision "shell", path: "C:/Users/balog/Desktop/vagrant-branch-client/provision.sh"
  end
end
</code></pre>
<h2 id="heading-script-provision-for-vagrant-file"><strong>Script provision for vagrant file</strong></h2>
<pre><code class="lang-plaintext">#!/bin/bash

# Update and install necessary packages
sudo apt-get update

# Install packages based on hostname
if [[ $(hostname) == "main" || $(hostname) == "branch" ]]; then
    sudo apt-get install -y bind9 bind9utils bind9-doc tinc

    if [[ $(hostname) == "branch" ]]; then
        sudo apt-get install -y isc-dhcp-server chrony
    fi
elif [[ $(hostname) == "client" ]]; then
    sudo apt-get install -y tinc chrony
fi

# Configure BIND9 for Main Server
if [[ $(hostname) == "main" ]]; then
    # BIND9 Configuration
    cat &lt;&lt;EOF | sudo tee /etc/bind/named.conf.local
zone "abc.local" {
    type master;
    file "/etc/bind/db.abc.local";
};

zone "5.168.192.in-addr.arpa" {
    type master;
    file "/etc/bind/db.192.168.5";
};
EOF

    cat &lt;&lt;EOF | sudo tee /etc/bind/db.abc.local
\$TTL    604800
@       IN      SOA     main.abc.local. admin.abc.local. (
                           2         ; Serial
                      604800         ; Refresh
                       86400         ; Retry
                     2419200         ; Expire
                      604800 )       ; Negative Cache TTL
;
@       IN      NS      main.abc.local.
main    IN      A       192.168.1.10
branch  IN      A       192.168.5.10
client  IN      A       192.168.5.15
EOF

    cat &lt;&lt;EOF | sudo tee /etc/bind/db.192.168.5
\$TTL    604800
@       IN      SOA     main.abc.local. admin.abc.local. (
                           2         ; Serial
                      604800         ; Refresh
                       86400         ; Retry
                     2419200         ; Expire
                      604800 )       ; Negative Cache TTL
;
@       IN      NS      main.abc.local.
10      IN      PTR     branch.abc.local.
15      IN      PTR     client.abc.local.
EOF

    cat &lt;&lt;EOF | sudo tee /etc/bind/named.conf.options
options {
    directory "/var/cache/bind";

    forwarders {
        8.8.8.8;
        8.8.4.4;
    };

    dnssec-validation auto;

    listen-on-v6 { any; };
};
EOF

    sudo systemctl start bind9

# Configure BIND9 for Branch Server
elif [[ $(hostname) == "branch" ]]; then
    # BIND9 Configuration
    cat &lt;&lt;EOF | sudo tee /etc/bind/named.conf.local
zone "abc.local" {
    type slave;
    file "/var/cache/bind/db.abc.local";
    masters { 192.168.1.10; };
};

zone "5.168.192.in-addr.arpa" {
    type slave;
    file "/var/cache/bind/db.192.168.5";
    masters { 192.168.1.10; };
};
EOF

    cat &lt;&lt;EOF | sudo tee /etc/bind/named.conf.options
options {
    directory "/var/cache/bind";

    forwarders {
        192.168.1.10;
    };

    dnssec-validation auto;

    listen-on-v6 { any; };
};
EOF

    sudo systemctl start bind9

    # Configure DHCP Server
    cat &lt;&lt;EOF | sudo tee /etc/dhcp/dhcpd.conf
option domain-name "company.local";
default-lease-time 600;
max-lease-time 7200;

subnet 192.168.5.0 netmask 255.255.255.0 {
    range 192.168.5.15 192.168.5.50;
    option routers 192.168.5.10;
    option domain-name-servers 192.168.5.10, 8.8.8.8;
}
EOF

    sudo sed -i 's/INTERFACESv4=""/INTERFACESv4="ens33"/' /etc/default/isc-dhcp-server

    sudo systemctl start isc-dhcp-server

    # Enable IP Forwarding and configure NAT
    sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
    sudo sysctl -p
    sudo iptables -t nat -A POSTROUTING -o ens38 -j MASQUERADE
    sudo iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
    sudo iptables -A FORWARD -j ACCEPT
    sudo sh -c "iptables-save &gt; /etc/iptables/rules.v4"
#    sudo apt-get install iptables-persistent -y

    # Configure Tinc VPN for Branch Server
    sudo mkdir -p /etc/tinc/vpn/hosts

    cat &lt;&lt;EOF | sudo tee /etc/tinc/vpn/tinc.conf
Name = branch
AddressFamily = ipv4
Interface = tun0
ConnectTo = main
EOF

    cat &lt;&lt;EOF | sudo tee /etc/tinc/vpn/tinc-up
#!/bin/sh
ifconfig \$INTERFACE 10.0.0.2 netmask 255.255.255.0
EOF

    cat &lt;&lt;EOF | sudo tee /etc/tinc/vpn/tinc-down
#!/bin/sh
ifconfig \$INTERFACE down
EOF

    sudo chmod +x /etc/tinc/vpn/tinc-up /etc/tinc/vpn/tinc-down

    cat &lt;&lt;EOF | sudo tee /etc/tinc/vpn/hosts/branch
Address = 192.168.5.10
Subnet = 10.0.0.2/32
EOF

    sudo tincd -n vpn -K4096
    sudo systemctl enable tinc@vpn
    sudo systemctl start tinc@vpn

# Client Configuration
elif [[ $(hostname) == "client" ]]; then
    # Configure Netplan
    cat &lt;&lt;EOF | sudo tee /etc/netplan/01-netcfg.yaml
network:
  version: 2
  ethernets:
    ens33:
      dhcp4: yes
      routes:
        - to: default
          via: 192.168.5.10
      nameservers:
        addresses:
          - 192.168.5.10
          - 8.8.8.8
EOF

    sudo netplan apply

    # Configure Chrony
    sudo sed -i '/pool /d' /etc/chrony/chrony.conf
    echo "server branch.abc.local iburst" | sudo tee -a /etc/chrony/chrony.conf
    sudo systemctl start chrony
    sudo systemctl enable chrony
fi

# Configure Chrony on Branch Server
if [[ $(hostname) == "branch" ]]; then
    sudo sed -i '/pool /d' /etc/chrony/chrony.conf
    echo "server main.abc.local prefer iburst" | sudo tee -a /etc/chrony/chrony.conf
    sudo systemctl start chrony
    sudo systemctl enable chrony
fi

# Common Configuration
# Set hostname and update /etc/hosts
sudo hostnamectl set-hostname $(hostname).abc.local
cat &lt;&lt;EOF | sudo tee -a /etc/hosts
192.168.1.10 main.abc.local
192.168.5.10 branch.abc.local
192.168.5.15 client.abc.local
EOF
</code></pre>
<p>This provisioner will set up BIND9 for both the main and branch servers, configure Tinc VPN, set up DHCP on the branch server, and provide internet access to the client.</p>
<h2 id="heading-5-start-the-vms"><strong>5. Start the VMs</strong></h2>
<pre><code class="lang-plaintext">vagrant up
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*hA5hKg4XL8pOjTWs" alt /></p>
<h2 id="heading-6-verify-the-vms"><strong>6. Verify the VMs</strong></h2>
<pre><code class="lang-plaintext">vagrant status
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*27h_MlJzmYhM0g46" alt /></p>
<h2 id="heading-use-vmware-workstation-to-discover-and-manage-the-running-vms"><strong>Use vmware workstation to discover and manage the running VMs</strong></h2>
<ul>
<li><p>Open vmware workstation, click on <code>File</code>, then select option <code>scan for virtual machines</code></p>
</li>
<li><p>Browse for the installation location of the created VMs, follow the instructions on screen and launch it.</p>
</li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*xK_dRcNBRap9hPzD" alt /></p>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*UYd6S-5bYfWd7ebg" alt /></p>
<h2 id="heading-verify-the-vms-on-the-vmware-workstation"><strong>Verify the VMs on the VMware workstation</strong></h2>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*teF2quzQrIjpSPRI" alt /></p>
<p><img src="https://miro.medium.com/v2/resize:fit:1050/0*ahyKLvbjmRA6JKcY" alt /></p>
<h2 id="heading-other-vagrant-commands"><strong>Other vagrant commands</strong></h2>
<pre><code class="lang-plaintext">vagrant halt #to halt the VM
vagrant destroy #to remove the VM setup
vagrant validate #to validate the configuration files in the vagrant directory
vagrant status #show status of vagrant VMs
</code></pre>
<h1 id="heading-in-conclusion"><strong>In Conclusion</strong></h1>
<p>Completing this scenario will provide you with practical experience in network administration, enabling you to apply the concepts and commands learned to address real-world challenges faced by Cloud Engineers and System Administrators.</p>
]]></content:encoded></item></channel></rss>