Student Manual — Module 2: Linux Security Configuration
Student Manual

# Linux Administration Essentials

## Module 2: Linux Security Configuration

LNX-001

1-day course · 5 modules · beginner level

### Learning Objectives

After completing this module, you will be able to:

- Configure SSH service for secure remote access
- Implement key-based authentication for passwordless login
- Manage firewall rules using Uncomplicated Firewall (ufw)
- Apply security best practices for system access control

# Lesson 1: Linux Security Architecture Overview

Linux systems implement security through multiple layers of defense, combining authentication (SSH keys, passwords), authorization (file permissions, sudo), and access control mechanisms (firewalls, SELinux). Understanding these layers is essential for building secure server environments.

Illustration of Linux security layers showing a protected server at the center, surrounded by concentric security barriers representing authentication, authorization, and firewall filtering

Key Takeaways

- Linux security uses multiple layers: authentication, authorization, and access control
- The principle of least privilege minimizes attack surface by limiting permissions
- SSH provides encrypted remote access, replacing insecure protocols
- Firewalls filter network traffic based on administrator-defined rules

# Lesson 2: SSH Service Architecture and Configuration

Added after 'Service Management with systemd' paragraph: 'Before modifying sshd_config, always create a backup: `sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup`. Test configuration syntax without applying changes using `sudo sshd -t`. In production, never restart SSH without confirming syntax is valid, as errors can lock you out of remote access.'

Illustration showing the SSH connection process from client to server, depicting the encrypted tunnel formation, authentication exchange, and secure session establishment

Key Takeaways

- sshd is the SSH server daemon that handles incoming connections
- Configuration is stored in /etc/ssh/sshd_config
- Service changes require reloading sshd with systemctl
- Running SSH on non-standard ports reduces automated attack attempts

# Lesson 3: SSH Key-Based Authentication

## SSH Key-Based Authentication

Key-based authentication is more secure than passwords and enables passwordless login. This method uses public-key cryptography to prove identity without transmitting secrets over the network.

### How Public Key Cryptography Works

You generate a key pair: a private key (kept secret on your client machine) and a public key (copied to servers you want to access). The private key never leaves your machine. When you connect, the server sends a challenge encrypted with your public key. Only your private key can decrypt it. By responding correctly, you prove you possess the private key without ever transmitting it.

### Generating SSH Key Pairs

The `ssh-keygen` command creates key pairs:

    ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

This generates a 4096-bit RSA key pair. You'll be prompted for a file location (default: `~/.ssh/id_rsa`) and an optional passphrase. The passphrase encrypts your private key on disk, adding a second layer of protection if your workstation is compromised.

### Deploying Public Keys

To enable key-based login, copy your public key to the target server's `~/.ssh/authorized_keys` file. The `ssh-copy-id` utility automates this:

    ssh-copy-id -i ~/.ssh/id_rsa.pub user@server

Alternatively, manually append the public key content to the remote file. Permissions are critical: `~/.ssh` must be mode 700, and `authorized_keys` must be mode 600. Incorrect permissions cause SSH to reject key-based authentication.

### Disabling Password Authentication

Once key-based authentication works, disable password authentication in `sshd_config` by setting `PasswordAuthentication no`. This prevents brute-force password attacks entirely, as only clients with valid private keys can connect.

Illustration depicting the public-private key relationship as a lock and key mechanism, showing how the public key encrypts challenges that only the private key can decrypt

Key Takeaways

- Key-based authentication uses public-key cryptography for passwordless login
- ssh-keygen creates key pairs; private keys stay on the client, public keys go to servers
- Public keys must be added to ~/.ssh/authorized_keys with correct permissions
- Disabling password authentication prevents brute-force attacks

# Lesson 4: Understanding Firewall Fundamentals

## Understanding Firewall Fundamentals

Firewalls are the first line of defense in network security, controlling which traffic can reach your system based on rules you define. Ubuntu's Uncomplicated Firewall (ufw) makes firewall management accessible to administrators at all skill levels.

### What Firewalls Do

A firewall inspects incoming and outgoing network packets, comparing them against a ruleset. Each rule specifies criteria (source IP, destination port, protocol) and an action (allow or deny). Packets matching a rule are handled according to that rule's action. Packets matching no rules are handled by the default policy.

### The ufw Philosophy

ufw wraps the powerful but complex iptables system with a simpler command-line interface. It's designed around a "deny by default" philosophy: when enabled, ufw blocks all incoming connections except those you explicitly allow. Outgoing connections are typically allowed, letting your applications reach external services.

### Default Policies

Before enabling ufw, set appropriate default policies:

    sudo ufw default deny incoming
    sudo ufw default allow outgoing

This configuration protects you from unwanted inbound connections while allowing your applications to function normally.

### Rule Processing Order

ufw processes rules in the order they're defined. When a packet matches a rule, that rule's action is taken immediately and no further rules are evaluated. This means more specific rules should come before more general ones. For example, if you want to allow SSH from a specific IP and deny it from everywhere else, the allow rule must be defined first.

### Application Profiles

ufw includes predefined application profiles for common services. Running `sudo ufw app list` shows available profiles. Instead of remembering that SSH uses port 22, you can simply run `sudo ufw allow OpenSSH`. Profiles make firewall management more intuitive.

Illustration of a firewall as a security checkpoint with guards inspecting incoming network packets against a rulebook, allowing some through and blocking others

Key Takeaways

- Firewalls filter network traffic based on administrator-defined rules
- ufw simplifies firewall management with an intuitive command-line interface
- Default deny incoming, allow outgoing is the recommended security posture
- Rules are processed in order; first match wins

# Lesson 5: Implementing UFW Firewall Rules

## Implementing UFW Firewall Rules

Effective firewall management requires understanding rule syntax, testing procedures, and troubleshooting techniques. This section covers practical ufw usage for common scenarios.

### Basic Rule Syntax

The most common ufw command allows traffic to a specific port:

    sudo ufw allow 2222/tcp

This permits incoming TCP connections on port 2222. You can also deny traffic:

    sudo ufw deny 23/tcp

Or delete existing rules:

    sudo ufw delete allow 2222/tcp

### Advanced Rule Options

Restrict access by source IP address:

    sudo ufw allow from 192.168.1.100 to any port 2222

This allows connections to port 2222 only from 192.168.1.100. You can also specify IP ranges using CIDR notation:

    sudo ufw allow from 192.168.1.0/24 to any port 2222

### Enabling and Managing the Firewall

After defining rules, enable ufw:

    sudo ufw enable

You'll see a warning about disrupting existing SSH connections. Ensure you've allowed SSH before enabling, or you may lock yourself out. Check status with:

    sudo ufw status verbose

This displays all active rules and default policies.

### Testing and Verification

After making changes, verify your rules work as expected. From a remote system, attempt connections to allowed and denied ports using `telnet` or `nc` (netcat). Monitor logs in `/var/log/ufw.log` to see blocked connection attempts. This helps confirm your firewall is functioning correctly and identify any configuration issues.

Before and after comparison showing a server vulnerable to many connection attempts versus a protected server with selective firewall rules allowing only authorized traffic

Key Takeaways

- Basic rule syntax: ufw allow/deny <port>/<protocol>
- Advanced rules can restrict by source IP address or network range
- Always allow SSH before enabling ufw to avoid lockouts
- Verify firewall rules by testing connections and reviewing logs

# Lesson 6: Security Hardening Best Practices

## Security Hardening Best Practices

Beyond basic configuration, security hardening involves implementing defense-in-depth strategies that make your system resilient against attacks.

### SSH Hardening Checklist

Implement these SSH security measures:

- Disable root login: Set `PermitRootLogin no` in sshd_config. Always use sudo with regular accounts.
- Change the default port: Run SSH on a non-standard port to reduce automated attacks.
- Use key-based authentication only: Set `PasswordAuthentication no` and `ChallengeResponseAuthentication no`.
- Limit user access: Use `AllowUsers` or `AllowGroups` directives to restrict who can connect.
- Set idle timeout: Configure `ClientAliveInterval` and `ClientAliveCountMax` to disconnect idle sessions.

### Firewall Best Practices

Maintain secure firewall configurations:

- Start with deny-all: Default deny incoming traffic, then explicitly allow necessary services.
- Document your rules: Maintain a record of why each firewall rule exists.
- Regular audits: Periodically review rules and remove those no longer needed.
- Use IP allowlists: When possible, restrict access to known IP addresses or ranges.
- Monitor logs: Regularly review firewall logs for suspicious activity patterns.

### System Update Practices

Keeping software current is critical for security:

    sudo apt update && sudo apt upgrade -y

Enable automatic security updates using the unattended-upgrades package. Security vulnerabilities are discovered regularly, and updates patch these vulnerabilities before attackers can exploit them.

### The Security Mindset

Security is not a one-time configuration but an ongoing process. Stay informed about new threats, regularly review your configurations, and assume compromise is possible. Build systems that limit damage even if one component is breached. This mindset—defense in depth—is your strongest protection.

Illustration showing a well-fortified server environment with multiple security layers including updated software shields, firewall barriers, and authentication gates, representing defense-in-depth strategy

Key Takeaways

- SSH hardening includes disabling root login, using key authentication, and changing default ports
- Firewall best practices emphasize default deny, regular audits, and IP allowlists
- Keep systems updated to patch security vulnerabilities
- Security is an ongoing process requiring vigilance and defense in depth

# Lab: Configuring SSH and Firewall Security

Objective: Configure SSH for key-based authentication and implement firewall rules to secure remote access to a Linux system

Estimated Time: 45 minutes

Platform: Ubuntu Linux VM on VirtualBox (Windows host)

Prerequisites:

- VirtualBox installed on Windows
- Ubuntu Linux VM created and running
- VM configured with network adapter in bridged or NAT mode
- Basic terminal command familiarity

## Procedures

### Step 1: Start your Ubuntu VM and open a terminal window

1. Launch VirtualBox on your Windows computer
2. Select your Ubuntu VM from the list
3. Click the Start button (green arrow)
4. Wait for Ubuntu to boot completely
5. Log in with your user credentials
6. Press `Ctrl+Alt+T` to open a terminal window

Verify you're logged in as a regular user (not root) by running:

    whoami

Expected Output:

Your username should be displayed (e.g., 'student', 'ubuntu', or whatever username you created during VM setup)

✔ Verification: The terminal prompt should show username@hostname format, such as 'student@ubuntu-vm:~$'

### Step 2: Check the current status of the SSH service

Verify that the SSH server (OpenSSH) is installed and check its running status:

    sudo systemctl status ssh

You'll be prompted for your password. Type it and press Enter (note: no characters will appear as you type for security).

If SSH is not installed, install it with:

    sudo apt update
    sudo apt install openssh-server -y

Expected Output:

You should see output containing:

    ● ssh.service - OpenBSD Secure Shell server
         Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
         Active: active (running) since ...

The key indicators are:

- Loaded: Shows the service is installed
- Active: active (running) means SSH is currently running
- enabled means it will start automatically on boot

✔ Verification: Look for 'Active: active (running)' in green text. If you see 'inactive (dead)', start the service with: sudo systemctl start ssh

### Step 3: Identify your VM's IP address

Find the IP address of your Ubuntu VM so you can connect to it via SSH:

    ip addr show

Alternatively, use the simpler command:

    hostname -I

Look for the IP address associated with your primary network interface (usually `enp0s3` or `eth0`). Ignore the loopback address (127.0.0.1).

Expected Output:

For the `hostname -I` command, you'll see an IP address like:

    192.168.1.150

For `ip addr show`, look for a section like:

    2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP
        inet 192.168.1.150/24 brd 192.168.1.255 scope global dynamic enp0s3

The IP address follows 'inet' (in this example: 192.168.1.150).

✔ Verification: Write down your VM's IP address - you'll need it for testing SSH connections. The address should be in the format xxx.xxx.xxx.xxx

### Step 4: Generate an SSH key pair for authentication

Create a new SSH key pair that will be used for passwordless authentication:

    ssh-keygen -t ed25519 -C "linux-lab-key"

When prompted:

1. Enter file in which to save the key: Press Enter to accept the default location (`/home/yourusername/.ssh/id_ed25519`)
2. Enter passphrase: Press Enter for no passphrase (for lab purposes only - in production, always use a passphrase)
3. Enter same passphrase again: Press Enter again

The `-t ed25519` option specifies the key type (modern, secure algorithm), and `-C` adds a comment to identify the key.

Expected Output:

    Generating public/private ed25519 key pair.
    Enter file in which to save the key (/home/student/.ssh/id_ed25519):
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in /home/student/.ssh/id_ed25519
    Your public key has been saved in /home/student/.ssh/id_ed25519.pub
    The key fingerprint is:
    SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx linux-lab-key
    The key's randomart image is:
    +--[ED25519 256]--+
    |    . .          |
    |   . = .         |
    [...art image...]
    +----[SHA256]-----+

✔ Verification: Verify the keys were created by listing the .ssh directory: ls -la ~/.ssh/ You should see both id_ed25519 (private key) and id_ed25519.pub (public key) files

### Step 5: Copy the public key to the authorized_keys file

Since we're setting up key-based authentication on the same machine (for learning purposes), copy your public key to the authorized_keys file:

    cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys

Then set the correct permissions on the authorized_keys file:

    chmod 600 ~/.ssh/authorized_keys

And verify the permissions on the .ssh directory:

    chmod 700 ~/.ssh

These permissions are critical for SSH security. The `700` permission means only the owner can read, write, and execute (access the directory). The `600` permission means only the owner can read and write the file.

Expected Output:

The commands produce no output if successful. To verify the key was added, run:

    cat ~/.ssh/authorized_keys

You should see your public key, which looks like:

    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx linux-lab-key

✔ Verification: Check permissions with: ls -la ~/.ssh/ The authorized_keys file should show -rw------- (600) and the .ssh directory should show drwx------ (700)

### Step 6: Test SSH key-based authentication locally

Test that key-based authentication works by connecting to localhost:

    ssh localhost

If this is your first time connecting, you'll see a message about the authenticity of the host. Type `yes` and press Enter to continue.

You should connect without being prompted for a password. Once connected, you'll see a new shell prompt.

To confirm you're in an SSH session, run:

    echo $SSH_CONNECTION

Then exit the SSH session:

    exit

Expected Output:

First connection:

    The authenticity of host 'localhost (127.0.0.1)' can't be established.
    ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    Warning: Permanently added 'localhost' (ED25519) to the list of known hosts.
    Welcome to Ubuntu 22.04.x LTS
    [...system information...]
    student@ubuntu-vm:~$

The `echo $SSH_CONNECTION` command will show:

    127.0.0.1 xxxxx 127.0.0.1 22

After `exit`, you return to your original shell.

✔ Verification: Success is indicated by connecting without a password prompt. If prompted for a password, review the previous steps, especially file permissions

### Step 7: Backup and edit the SSH daemon configuration file

Before modifying the SSH server configuration, create a backup:

    sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

Now open the configuration file with a text editor:

    sudo nano /etc/ssh/sshd_config

In the nano editor:

1. Press `Ctrl+W` to search
2. Type `PasswordAuthentication` and press Enter
3. You'll find a line that says `#PasswordAuthentication yes` or `PasswordAuthentication yes`
4. Change it to: `PasswordAuthentication no` (remove the # if present)
5. Press `Ctrl+W` again and search for `PermitRootLogin`
6. Change it to: `PermitRootLogin no`
7. Press `Ctrl+X` to exit, then `Y` to save, then Enter to confirm the filename

Expected Output:

The backup command produces no output if successful. You can verify with:

    ls -l /etc/ssh/sshd_config*

Which shows:

    -rw-r--r-- 1 root root 3289 Nov 15 10:30 /etc/ssh/sshd_config
    -rw-r--r-- 1 root root 3289 Nov 15 09:15 /etc/ssh/sshd_config.backup

In nano, the bottom shows available commands. After saving, nano displays:

    File Name to Write: /etc/ssh/sshd_config

✔ Verification: Verify your changes with: sudo grep -E '^PasswordAuthentication|^PermitRootLogin' /etc/ssh/sshd_config You should see both settings uncommented (no #) and set to 'no'

### Step 8: Restart the SSH service to apply configuration changes

Restart the SSH daemon to load the new configuration:

    sudo systemctl restart ssh

Then verify the service restarted successfully:

    sudo systemctl status ssh

Press `q` to exit the status display.

Important: In a production environment, always test your SSH configuration before restarting to avoid locking yourself out. You can test the configuration with:

    sudo sshd -t

This command checks for syntax errors without actually applying changes.

Expected Output:

The restart command produces no output if successful.

The status command shows:

    ● ssh.service - OpenBSD Secure Shell server
         Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
         Active: active (running) since [current timestamp]
         Process: 1234 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
        Main PID: 1235 (sshd)

The configuration test (`sshd -t`) produces no output if the configuration is valid.

✔ Verification: The service status should show 'Active: active (running)' in green. The timestamp should be recent (within the last minute), confirming the restart occurred

### Step 9: Check the status of the Uncomplicated Firewall (UFW)

Check if UFW is installed and its current status:

    sudo ufw status

If UFW is not installed, install it:

    sudo apt update
    sudo apt install ufw -y

UFW is typically installed by default on Ubuntu but disabled initially to prevent accidental lockouts.

Expected Output:

If UFW is installed but inactive:

    Status: inactive

If UFW is already active (less common on a new installation):

    Status: active

    To                         Action      From
    --                         ------      ----
    22/tcp                     ALLOW       Anywhere
    22/tcp (v6)               ALLOW       Anywhere (v6)

✔ Verification: The command should execute without errors. If you see 'command not found', UFW needs to be installed

### Step 10: Configure UFW to allow SSH connections before enabling the firewall

Critical step: Before enabling UFW, you must allow SSH connections to prevent being locked out of your system:

    sudo ufw allow ssh

This command adds a rule to allow connections on port 22 (the default SSH port). You can also use the port number directly:

    sudo ufw allow 22/tcp

Both commands accomplish the same thing. The first uses the service name, the second uses the port and protocol explicitly.

Expected Output:

    Rules updated
    Rules updated (v6)

The message appears twice because UFW adds rules for both IPv4 and IPv6.

✔ Verification: Verify the rule was added by checking UFW status: sudo ufw status Even though UFW is still inactive, it will show 'Rules updated' confirming the rule is staged

### Step 11: Enable the UFW firewall

Now that SSH access is allowed, enable the firewall:

    sudo ufw enable

You'll see a warning message about disrupting existing SSH connections. Since we've already added the SSH allow rule, type `y` and press Enter to proceed.

Then check the firewall status:

    sudo ufw status verbose

The `verbose` option provides additional details about the firewall configuration.

Expected Output:

When enabling:

    Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
    Firewall is active and enabled on system startup

The verbose status shows:

    Status: active
    Logging: on (low)
    Default: deny (incoming), allow (outgoing), disabled (routed)
    New profiles: skip

    To                         Action      From
    --                         ------      ----
    22/tcp                     ALLOW IN    Anywhere
    22/tcp (v6)               ALLOW IN    Anywhere (v6)

✔ Verification: Confirm 'Status: active' appears at the top of the output and port 22/tcp shows 'ALLOW IN' for both IPv4 and IPv6

### Step 12: Add additional firewall rules for common services

Practice adding more firewall rules. Allow HTTP (web) traffic:

    sudo ufw allow 80/tcp

Allow HTTPS (secure web) traffic:

    sudo ufw allow 443/tcp

You can also allow services by name. Allow HTTP using the service name:

    sudo ufw allow http

Note: This will show the rule already exists since we just added port 80.

View all current rules with numbers:

    sudo ufw status numbered

Expected Output:

For each allow command:

    Rules updated
    Rules updated (v6)

For the numbered status:

    Status: active

         To                         Action      From
         --                         ------      ----
    [ 1] 22/tcp                     ALLOW IN    Anywhere
    [ 2] 80/tcp                     ALLOW IN    Anywhere
    [ 3] 443/tcp                    ALLOW IN    Anywhere
    [ 4] 22/tcp (v6)               ALLOW IN    Anywhere (v6)
    [ 5] 80/tcp (v6)               ALLOW IN    Anywhere (v6)
    [ 6] 443/tcp (v6)               ALLOW IN    Anywhere (v6)

✔ Verification: Each rule should appear twice in the list - once for IPv4 and once for IPv6 (marked with 'v6')

### Step 13: Test denying a specific port and verify firewall behavior

Practice denying access to a specific port. Deny access to port 8080:

    sudo ufw deny 8080/tcp

Check the status:

    sudo ufw status numbered

You can also delete rules if needed. To delete a rule by number (don't do this for rule 1, which is SSH):

    sudo ufw delete 2

When prompted, type `y` and press Enter. This demonstrates rule management, but we're deleting rule 2 (port 80) as an example only.

After experimenting, re-add the HTTP rule:

    sudo ufw allow 80/tcp

Expected Output:

When denying port 8080:

    Rules updated
    Rules updated (v6)

Deleting a rule:

    Deleting:
     allow 80/tcp
    Proceed with operation (y|n)? y
    Rule deleted
    Rule deleted (v6)

Final status shows the updated ruleset with port 8080 denied and port 80 re-added.

✔ Verification: Run sudo ufw status to confirm port 8080 shows 'DENY IN' and port 80 shows 'ALLOW IN'

### Step 14: Configure UFW default policies

View and understand the default policies. UFW's default policies determine what happens to traffic that doesn't match any specific rule:

    sudo ufw status verbose

The default policies are shown in the output. The standard secure configuration is:

- Default incoming: deny
- Default outgoing: allow
- Default routed: disabled

This means:

- All incoming connections are blocked unless explicitly allowed
- All outgoing connections are permitted
- Routing/forwarding between interfaces is disabled

These defaults are already set, but you could change them with:

    sudo ufw default deny incoming
    sudo ufw default allow outgoing

Expected Output:

The verbose status shows:

    Status: active
    Logging: on (low)
    Default: deny (incoming), allow (outgoing), disabled (routed)
    New profiles: skip

If you run the default commands:

    Default incoming policy changed to 'deny'
    (be sure to update your rules accordingly)
    Default outgoing policy changed to 'allow'
    (be sure to update your rules accordingly)

✔ Verification: The 'Default:' line should show 'deny (incoming), allow (outgoing)' - this is the most secure basic configuration

### Step 15: Review UFW logs and verify firewall is protecting the system

UFW logs blocked connection attempts. View recent UFW log entries:

    sudo tail -20 /var/log/ufw.log

If the log file doesn't exist or is empty (common on new installations with no blocked attempts), that's normal.

You can also check the general system log for UFW messages:

    sudo journalctl -u ufw --no-pager | tail -20

To generate a test log entry, try connecting to the denied port 8080 from localhost:

    telnet localhost 8080

Press `Ctrl+]` then type `quit` if telnet connects (it shouldn't). If telnet is not installed, that's fine - the attempt would be blocked anyway.

Finally, document your firewall configuration:

    sudo ufw status numbered > ~/firewall-config.txt
    cat ~/firewall-config.txt

Expected Output:

UFW log entries (if any) look like:

    [UFW BLOCK] IN=enp0s3 OUT= MAC=... SRC=192.168.1.100 DST=192.168.1.150 PROTO=TCP DPT=8080

Journalctl output shows:

    Nov 15 14:23:45 ubuntu-vm systemd[1]: Starting Uncomplicated firewall...
    Nov 15 14:23:45 ubuntu-vm systemd[1]: Started Uncomplicated firewall.

The telnet test (if blocked) shows:

    Trying 127.0.0.1...
    telnet: Unable to connect to remote host: Connection refused

The firewall-config.txt file contains your numbered rules list.

✔ Verification: The firewall-config.txt file should exist in your home directory with a complete list of active rules. Verify with: ls -l ~/firewall-config.txt

## Troubleshooting

Problem: SSH service fails to start with error 'Address already in use'
Solution: Another process is using port 22. Find it with: sudo lsof -i :22 If you see multiple sshd processes, kill the old ones: sudo pkill sshd Then start SSH again: sudo systemctl start ssh
Problem: After enabling UFW, SSH connection is refused
Solution: You likely enabled UFW without allowing SSH first. From the VM console (not SSH), run: sudo ufw allow 22/tcp && sudo ufw reload If you're completely locked out, boot into recovery mode, disable UFW (sudo ufw disable), reboot, then re-configure properly
Problem: ssh-keygen command not found
Solution: OpenSSH client tools are not installed. Install them with: sudo apt update && sudo apt install openssh-client -y Then retry the ssh-keygen command
Problem: Permission denied (publickey) when testing SSH connection
Solution: Check file permissions: ls -la ~/.ssh/ The .ssh directory should be 700 (drwx------) and authorized_keys should be 600 (-rw-------). Fix with: chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys Also verify the public key was correctly copied to authorized_keys: cat ~/.ssh/authorized_keys
Problem: Cannot edit /etc/ssh/sshd_config - 'Permission denied' error
Solution: You must use sudo to edit system configuration files. Use: sudo nano /etc/ssh/sshd_config If you forgot to use sudo and made changes, those changes weren't saved. Start over with sudo

## Challenge Exercise

### Implement Port Knocking Simulation

Now that you understand SSH and firewall basics, implement a more advanced security configuration:

Your challenge:

1. Change SSH to listen on a non-standard port (choose any port above 1024, such as 2222)
2. Update your firewall rules to block the standard SSH port (22) and allow your new custom port
3. Configure UFW to rate-limit SSH connections on your custom port to prevent brute-force attacks (hint: use the `limit` action instead of `allow`)
4. Set up UFW logging to HIGH level and generate a test connection to view detailed logs
5. Create a bash script named `ssh-status.sh` in your home directory that displays:
   - Current SSH port from sshd_config
   - Whether SSH service is running
   - Current UFW rules related to SSH
   - Number of active SSH connections

Success criteria:

- SSH service runs on your custom port
- You can connect using: `ssh -p [your-port] localhost`
- Port 22 is blocked in UFW
- Your custom port has rate limiting enabled
- The script executes and displays all requested information

Hints:

- The SSH port setting is called 'Port' in sshd_config
- Rate limiting syntax: `sudo ufw limit [port]/tcp`
- Use `ss -tn` or `netstat` to check active connections
- Remember to restart SSH after configuration changes
- Test thoroughly before closing your current terminal!

# Practice Questions

1. What is the primary advantage of key-based authentication over password authentication for SSH?

A) Key-based authentication never requires entering a passphrase

B) Private keys never leave the client machine, reducing exposure of credentials

C) Key-based authentication is faster than password authentication

D) Public keys are more secure than private keys

2. After modifying the /etc/ssh/sshd_config file, what command must you run to apply the changes?

A) sudo restart sshd

B) sudo systemctl reload sshd

C) sudo ufw reload

D) sudo ssh --reload

3. What is the correct file permission mode for the ~/.ssh/authorized_keys file?

A) 755 (rwxr-xr-x)

B) 644 (rw-r--r--)

C) 600 (rw-------)

D) 777 (rwxrwxrwx)

4. Which ufw command would allow SSH connections only from the IP address 192.168.1.50?

A) sudo ufw allow ssh from 192.168.1.50

B) sudo ufw allow from 192.168.1.50 to any port 22

C) sudo ufw allow 192.168.1.50:22

D) sudo ufw permit 192.168.1.50 port 22

5. What is the primary purpose of running SSH on a non-standard port (not 22)?

A) To improve SSH connection speed

B) To reduce automated port scans and opportunistic attacks

C) To encrypt SSH traffic more securely

D) To allow multiple SSH services on one server

6. What does the principle of least privilege mean in Linux security?

A) Users should have the minimum permissions necessary to perform their tasks

B) Root access should be granted to all administrators

C) All services should run with maximum permissions for flexibility

D) Security should be minimally configured to avoid complexity

7. In the SSH public key authentication workflow, what does the server use to verify the client's identity?

A) The client's private key sent over the encrypted connection

B) A challenge encrypted with the client's public key that only the matching private key can decrypt

C) The client's password hash stored in /etc/shadow

D) The server's private key compared against the client's public key

8. Which sshd_config directive should be set to 'no' to prevent brute-force password attacks entirely?

A) PermitRootLogin

B) PubkeyAuthentication

C) PasswordAuthentication

D) ChallengeResponseAuthentication

9. What is the recommended default policy for incoming traffic when configuring ufw?

A) Allow all incoming traffic by default

B) Deny all incoming traffic by default

C) Allow incoming traffic only on even-numbered ports

D) Route all incoming traffic through a proxy

10. When ufw processes firewall rules, what happens when a packet matches a rule?

A) All rules are evaluated and the most specific one is applied

B) The rule's action is taken immediately and no further rules are evaluated

C) The packet is logged and then passed to the next rule

D) The default policy is applied regardless of the matching rule

# Module Summary

This module covered essential Linux security practices, focusing on three critical areas: SSH configuration for secure remote access, key-based authentication for passwordless login, and firewall management using ufw. You learned how to configure the SSH daemon, generate and deploy cryptographic key pairs, implement the principle of least privilege, and control network access through firewall rules. These foundational security skills form the basis for maintaining secure Linux server environments. The combination of encrypted communication, strong authentication, and network filtering creates defense-in-depth protection against common attack vectors.