PROJECT GUIDE · 06

Secure the Enterprise Cloud Environment

Implement a complete Identity and Access Management (IAM) strategy using Linux users, groups, and sudo policies. Configure SSH key-based authentication, manage secrets securely, enable audit logging, and enforce encryption — building a security posture equivalent to cloud enterprise security standards.

Environment
Ubuntu VMs in VirtualBox
Linux IAM + SSH + Vault
Difficulty
⭐⭐⭐⭐ Intermediate–Advanced
First security-focused project
Course Module
Chapter 7
Cloud Security & Governance
Duration
4–5 Days
IAM + MFA + Encryption + Audit

1. Security Architecture – Defense in Depth

Cloud security is not a single wall — it is multiple overlapping layers of protection. If an attacker defeats one layer, the next layer stops them. This is called "defense in depth." In this project, you will implement all key layers: identity (who you are), access control (what you can do), encryption (protecting data), secrets management (protecting credentials), and audit logging (knowing what happened).

DEFENSE IN DEPTH — ABC RETAIL SECURITY LAYERS LAYER 6: NETWORK PERIMETER (Firewall / UFW — Project 4) LAYER 5: IDENTITY — Who can log in? (Linux Users + SSH Keys) LAYER 4: ACCESS CONTROL — What can they do? (sudo + Groups) LAYER 3: ENCRYPTION — Is data protected? (SSH-TLS + file encryption) LAYER 2: SECRETS — Are credentials safe? (ENV vars + Vault) 🔒 PROTECTED ASSET abc_retail database · customer PII · payment records AUDIT LOGGING EVERYWHERE: Every action recorded in /var/log/auth.log + custom audit trail

2. Step-by-Step Action Items

PHASE 1 · STEP 1 Implement IAM – Create Users, Groups, and Roles

In cloud platforms, IAM (Identity and Access Management) controls who can access what resources. AWS IAM has Users, Groups, and Policies. Azure AD has Users, Groups, and Role Assignments. Linux has the same concept: users, groups, and sudo policies. The principle is identical — the implementation differs slightly.

1
Create a security design document first. Add this IAM plan to your documentation:
UserRole / GroupPermissionsCloud Equivalent
cloudadminsudoFull system accessAWS Root / Global Admin
webdevwebteamRead/write web files onlyDeveloper Role
dbadmindbaDatabase access onlyDB Administrator Role
devopsdevops,dockerDocker + deploymentsDevOps Engineer Role
auditorreadonlyRead logs and configs onlySecurity Auditor Role
2
Create all groups first (groups define what a role can do):
sudo groupadd webteam sudo groupadd dba sudo groupadd devops sudo groupadd readonly # Verify groups were created cat /etc/group | grep -E "(webteam|dba|devops|readonly)"
In Linux, a group is a named collection of users that share the same permissions. File and directory permissions are set for the owner user, the owner group, and everyone else. Creating groups before users is best practice because it allows you to add users to groups immediately upon creation. The /etc/group file stores the group database — checking it confirms the groups exist. This mirrors how cloud IAM groups are created before users are assigned to them.
3
Create each user with appropriate settings:
# Web Developer - access to web files only sudo useradd -m -s /bin/bash -G webteam -c "Web Developer" webdev echo "webdev:WebDev@SecurePass2024" | sudo chpasswd # Database Administrator sudo useradd -m -s /bin/bash -G dba -c "Database Administrator" dbadmin echo "dbadmin:DBASecure@Pass2024" | sudo chpasswd # DevOps Engineer - can run Docker sudo useradd -m -s /bin/bash -G devops,docker -c "DevOps Engineer" devops echo "devops:DevOps@SecurePass2024" | sudo chpasswd # Security Auditor - read-only access sudo useradd -m -s /bin/bash -G readonly -c "Security Auditor" auditor echo "auditor:Audit@ReadOnly2024" | sudo chpasswd # List all users created cut -d: -f1,4,5 /etc/passwd | tail -10
The useradd command creates a new user. Breaking down the flags: -m creates a home directory (/home/username/), -s /bin/bash sets bash as the default shell, -G groupname adds the user to supplementary groups, -c "description" adds a comment (full name or role). The chpasswd command sets passwords for multiple users from stdin. The cut command extracts specific fields from /etc/passwd to verify user creation. Notice the devops user is added to the docker group — this gives permission to run Docker without sudo, exactly as you did for your main user in Project 3.
4
Configure sudo policies — what each role can do as administrator:
sudo visudo -f /etc/sudoers.d/abc-retail
The visudo command safely edits sudo configuration files — it checks for syntax errors before saving, preventing a corrupted sudoers file that would lock you out of administrative access. We use -f /etc/sudoers.d/abc-retail to create a separate file for ABC Retail's policies (rather than editing the main /etc/sudoers), following the modular configuration best practice.
5
In the visudo editor, add these policies and save:
# ABC Retail IAM Policies # Format: user/group host=(runas) NOPASSWD:commands # DevOps team can restart services and run Docker %devops ALL=(ALL) NOPASSWD: /usr/bin/docker, /bin/systemctl restart nginx, /bin/systemctl restart haproxy # DBA team can manage MariaDB only %dba ALL=(ALL) NOPASSWD: /bin/systemctl restart mariadb, /usr/bin/mysqldump, /usr/bin/mysql # Read-only auditors can only read logs %readonly ALL=(ALL) NOPASSWD: /bin/cat /var/log/*, /usr/bin/tail /var/log/*, /usr/bin/journalctl
These sudoers entries implement the principle of Least Privilege — each role has ONLY the minimum permissions needed to do their job. The %devops format means "the devops GROUP". NOPASSWD: allows these specific commands without re-entering a password. ALL=(ALL) means "on all hosts, as any user". Notice the DBA team can restart MariaDB and run mysqldump but cannot touch the web server or Docker. An auditor can only read logs — they cannot modify anything. This directly corresponds to how AWS IAM policies grant specific action permissions on specific resources.
6
Test the permissions by switching to different users:
# Switch to devops user and verify Docker access sudo su - devops docker ps # Should work (member of docker group) sudo systemctl restart nginx # Should work (in sudoers) sudo systemctl restart mariadb # Should FAIL (not in DBA sudoers) exit # Switch to auditor and test sudo su - auditor sudo cat /var/log/auth.log | tail -5 # Should work sudo systemctl restart nginx # Should FAIL (not permitted) exit
Testing permissions is just as important as setting them. A security configuration that isn't tested may have mistakes — the DevOps user might accidentally have too many permissions, or not enough to do their job. Each test that FAILS (returns "permission denied") is equally important to verify as tests that succeed. Document all test results in your security validation report.
PHASE 1 · STEP 2 Configure SSH Key-Based Authentication (MFA Simulation)

Password-based SSH authentication is vulnerable to brute-force attacks — automated tools can try millions of passwords per minute. SSH key-based authentication uses a cryptographic key pair: a public key (stored on the server) and a private key (kept securely on your laptop). Without the private key, access is impossible — this is equivalent to MFA because it requires something you HAVE (the key file) in addition to something you KNOW (the optional passphrase).

1
Generate an SSH key pair on your host machine (Windows PowerShell or Linux terminal):
# Run this on your HOST computer (Windows PowerShell or macOS Terminal) ssh-keygen -t ed25519 -C "cloudadmin@abc-retail.com" -f ~/.ssh/abc-retail-key # When prompted: # Enter passphrase: type a strong passphrase (optional but recommended) # Enter same passphrase again: repeat it # List the generated key files ls -la ~/.ssh/abc-retail-key*
The ssh-keygen command generates a cryptographic key pair. -t ed25519 specifies the Ed25519 algorithm — more secure and faster than the older RSA algorithm. -C "comment" adds an identifying comment to the public key. -f ~/.ssh/abc-retail-key specifies the output filename. After running this, you'll have two files: abc-retail-key (private key — NEVER share this) and abc-retail-key.pub (public key — this goes on the server). The passphrase adds an additional layer: even if someone steals the private key file, they need the passphrase to use it.
2
Copy the public key to the VM:
# From your HOST computer - copy public key to the VM # Replace [VM-IP] with your actual VM IP address # On Windows PowerShell: type $HOME\.ssh\abc-retail-key.pub | ssh cloudadmin@[VM-IP] "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" # On macOS/Linux Terminal: ssh-copy-id -i ~/.ssh/abc-retail-key.pub cloudadmin@[VM-IP]
The public key is added to ~/.ssh/authorized_keys on the server. When you SSH to the server, it sends a cryptographic challenge that only the holder of the matching private key can answer. This eliminates the need for password authentication entirely. In AWS, you select an "EC2 Key Pair" when launching an instance — this is the same concept: AWS stores your public key and the instance uses it to authenticate your connections.
3
Test key-based login from your host machine:
ssh -i ~/.ssh/abc-retail-key cloudadmin@[VM-IP]
The -i flag specifies which private key to use. If you set a passphrase, you'll be prompted for it — this is the "something you know" factor. The server checks your key against authorized_keys — this is the "something you have" factor. Two factors = MFA. You should log in WITHOUT entering the server password. If you still see a password prompt, the key wasn't set up correctly.
4
Disable password authentication to force key-only login (this is a critical security hardening step):
sudo nano /etc/ssh/sshd_config
5
Find and change these settings in sshd_config:
# Change these values (remove the # if there is one in front): PasswordAuthentication no PubkeyAuthentication yes PermitRootLogin no MaxAuthTries 3 LoginGraceTime 20
Each of these settings is a security hardening measure: PasswordAuthentication no — disables password login entirely (key-only). PermitRootLogin no — the root user cannot log in via SSH at all (even with a key). If an attacker wants root access, they must first log in as a regular user and then use sudo. MaxAuthTries 3 — disconnect after 3 failed attempts (limits brute-force attacks). LoginGraceTime 20 — disconnect if the user hasn't authenticated within 20 seconds. These are the same settings enabled by default on AWS and Azure virtual machines.
6
Save and restart SSH (make sure your key works BEFORE doing this, or you'll be locked out):
sudo systemctl restart sshd # Test from another terminal session BEFORE closing this one
⚠ CRITICAL: Open a second SSH session BEFORE closing the first After restarting sshd with PasswordAuthentication disabled, if your key doesn't work, you need the first session as a lifeline. Only close the original session after confirming key-based login works in the second session.
PHASE 2 · STEP 1 Implement Secrets Management with HashiCorp Vault

Secrets (passwords, API keys, database credentials) must never be stored in plain text files, code repositories, or environment variables in config files. HashiCorp Vault is the industry-standard secrets management tool — equivalent to AWS Secrets Manager or Azure Key Vault. You will run Vault locally in development mode to understand how it works.

1
Run HashiCorp Vault as a Docker container:
docker run -d \ --name vault \ -p 8200:8200 \ --cap-add=IPC_LOCK \ -e 'VAULT_DEV_ROOT_TOKEN_ID=abc-retail-dev-token' \ -e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200' \ hashicorp/vault:latest
We run Vault in development mode (VAULT_DEV_ROOT_TOKEN_ID sets a fixed root token for easy access). The --cap-add=IPC_LOCK flag allows Vault to lock memory pages, preventing the kernel from swapping sensitive data to disk — critical for a secrets manager. In production, Vault is run in HA (High Availability) mode with proper initialization and unsealing, but dev mode is sufficient for learning. Vault is available at http://[VM-IP]:8200.
2
Install the Vault CLI to interact with it from the terminal:
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list sudo apt update && sudo apt install vault -y
3
Configure the Vault CLI to connect to your running instance:
export VAULT_ADDR='http://127.0.0.1:8200' export VAULT_TOKEN='abc-retail-dev-token' # Verify connectivity vault status
4
Store all ABC Retail secrets in Vault (replacing plain text config files):
# Enable the KV (Key-Value) secrets engine vault secrets enable -path=abc-retail kv-v2 # Store database credentials vault kv put abc-retail/database \ host="192.168.56.102" \ port="3306" \ database="abc_retail" \ username="retailapp" \ password="AppDB@Pass2024!" # Store MinIO credentials vault kv put abc-retail/minio \ endpoint="http://localhost:9000" \ access_key="minioadmin" \ secret_key="MinioPass@2024" \ bucket="abc-retail-products" # Store MariaDB root password (for backup script) vault kv put abc-retail/mariadb-root \ password="YourActualRootPasswordHere" # Retrieve a secret to verify it works vault kv get abc-retail/database
The KV (Key-Value) secrets engine stores secrets as key-value pairs. Version 2 (kv-v2) maintains a history of every secret version — you can see previous values and roll back if needed. Vault encrypts all stored secrets using AES-256-GCM. When an application needs the database password, it authenticates with Vault and retrieves the secret at runtime — the password never exists as plain text in any config file or code repository. The vault kv get command shows all stored keys in a secret path, proving the credentials are accessible but protected.
5
Update the backup script to retrieve passwords from Vault instead of hardcoding them:
sudo nano /usr/local/bin/abc-retail-backup.sh
6
Replace the hardcoded password line with Vault retrieval:
# OLD (insecure - hardcoded password): # DB_PASS="YourRootPasswordHere" # NEW (secure - retrieved from Vault): export VAULT_ADDR='http://127.0.0.1:8200' export VAULT_TOKEN='abc-retail-dev-token' DB_PASS=$(vault kv get -field=password abc-retail/mariadb-root)
Now the backup script retrieves the database password from Vault at runtime — the password is never stored in the script itself. If an attacker gains access to the script file, they don't get the password. If the password needs to be rotated (changed for security), only the Vault entry is updated — all scripts and applications that retrieve it from Vault automatically use the new password without any code changes. This is the professional secret management pattern used at scale by large organizations.
PHASE 2 · STEP 2 Implement Data Encryption at Rest and in Transit

Encryption protects data in two states: "at rest" (stored on disk) and "in transit" (traveling over the network). Cloud providers encrypt everything by default, but engineers must understand which encryption is in place and verify it is configured correctly.

1
Encrypt sensitive backup files using GPG:
# Install GPG (may already be installed) sudo apt install gnupg -y # Generate a GPG key pair for ABC Retail backup encryption gpg --batch --gen-key <
GPG (GNU Privacy Guard) implements the OpenPGP encryption standard. A 4096-bit RSA key provides strong encryption that would take thousands of years to break with current computing power. We generate a key pair: the public key encrypts backup files, and the private key decrypts them. Only someone with the private key (and its passphrase) can access the encrypted backup data. This is "encryption at rest" — even if someone steals the backup file from disk, they cannot read it.
2
Encrypt a backup file to test the process:
# Create a test file echo "Sensitive ABC Retail customer data" > /tmp/test-data.txt # Encrypt it gpg --recipient "backup@abc-retail.com" --encrypt /tmp/test-data.txt # The encrypted file is test-data.txt.gpg ls -la /tmp/test-data.txt.gpg # Decrypt to verify (requires private key) gpg --decrypt /tmp/test-data.txt.gpg
After encryption, the .gpg file contains binary encrypted data — completely unreadable without the private key. The gpg --decrypt command uses the matching private key (stored in your GPG keyring) to decrypt the file. In production, the private key would be stored in a Hardware Security Module (HSM) or Vault, accessible only to authorized backup restoration processes.
3
Configure MariaDB to use encrypted connections:
# Generate SSL certificates for MariaDB sudo mysql_ssl_rsa_setup --uid=mysql # Verify SSL certificates were created ls -la /var/lib/mysql/*.pem # Verify SSL is enabled in MariaDB sudo mysql -u root -p -e "SHOW VARIABLES LIKE '%ssl%';"
MariaDB supports TLS/SSL encryption for connections between the web server and database. The mysql_ssl_rsa_setup command generates the necessary SSL certificates. When the application connects with REQUIRE SSL in the connection string, all data transmitted between the web server and database is encrypted — preventing network interception attacks (man-in-the-middle). This is "encryption in transit."
PHASE 3 · STEP 1 Enable Security Audit Logging

Audit logs record who did what, when, and from where. They are essential for security investigations ("who deleted those records?"), compliance audits (GDPR, PCI-DSS, SOC2), and detecting unauthorized access. Cloud services like AWS CloudTrail and Azure Monitor provide this — you will implement it manually to understand what information is captured.

1
View existing Linux authentication logs:
sudo grep "sshd\|sudo\|auth" /var/log/auth.log | tail -30
The /var/log/auth.log file records all authentication events: SSH logins (successful and failed), sudo commands, su (switch user) events, and PAM authentication events. Every entry includes a timestamp, hostname, process name, and details. This is your security event log — equivalent to AWS CloudTrail's "Who called what API and when?" This log is the first place security engineers check during an incident investigation.
2
Install and configure auditd for comprehensive command auditing:
sudo apt install auditd audispd-plugins -y sudo systemctl enable auditd sudo systemctl start auditd
The Linux Audit daemon (auditd) provides much more detailed logging than the standard auth.log. It can record every system call made to the kernel, including file reads/writes, process execution, and network connections. This is the equivalent of enabling AWS CloudTrail's detailed management events — it increases log volume but provides forensic-level detail for security investigations.
3
Configure audit rules for ABC Retail security monitoring:
sudo auditctl -w /etc/passwd -p wa -k user-management sudo auditctl -w /etc/sudoers -p wa -k privilege-change sudo auditctl -w /var/www/abc-retail -p rwxa -k web-file-access sudo auditctl -w /data/abc-retail/backups -p rwa -k backup-access sudo auditctl -w /etc/ssh/sshd_config -p wa -k ssh-config-change
Each auditctl -w rule watches a specific file or directory: -p wa logs write and attribute-change events, -p rwxa logs read, write, execute, and attribute changes. -k keyword adds a searchable tag to the event. These rules create audit trails for: changes to user accounts (/etc/passwd), privilege escalation changes (/etc/sudoers), web file modifications, backup file access, and SSH configuration changes. If a security incident occurs, you can search for the specific audit key to see all relevant events.
4
Search audit logs for specific events:
# Search by audit key sudo ausearch -k user-management sudo ausearch -k web-file-access # Generate an audit report sudo aureport --summary sudo aureport --auth
The ausearch tool queries audit logs by key, timestamp, user, or event type. aureport generates summary reports. These tools turn thousands of raw audit log entries into actionable security intelligence — which users are making changes, how many failed login attempts occurred, which files are being accessed most frequently. This is equivalent to the query and analysis features of cloud security services like AWS GuardDuty or Azure Defender for Servers.

3. Security Operations Pipeline

👤 IDENTITY Users + Groups SSH Keys 🔐 ACCESS sudo policies Least Privilege 🔑 SECRETS HashiCorp Vault No hardcoding 🔒 ENCRYPT GPG at rest TLS in transit 📋 AUDIT auditd rules auth.log 🛡 SECURE ✓ Zero Trust Compliant Principle of Least Privilege · Defense in Depth · Everything Logged

4. Security Configuration Templates

security-audit.sh — Run Weekly Security Checks
#!/bin/bash # ABC Retail Weekly Security Audit Script echo "=== ABC RETAIL SECURITY AUDIT REPORT ===" echo "Date: $(date)" echo "" # 1. Check for users with no password set echo "--- Users with empty passwords ---" sudo awk -F: '($2 == "" )' /etc/shadow # 2. List users with sudo access echo "--- Sudo Users ---" sudo grep -v '^#' /etc/sudoers | grep -v '^$' # 3. Check for failed login attempts in last 24h echo "--- Failed Login Attempts (last 24h) ---" sudo grep "Failed password" /var/log/auth.log | \ grep "$(date +'%b %d')" | wc -l # 4. Check for listening ports echo "--- Open Ports ---" sudo ss -tlnp # 5. Check UFW status echo "--- Firewall Rules ---" sudo ufw status verbose # 6. Verify SSH config is secure echo "--- SSH Security Settings ---" grep -E "(PasswordAuth|PermitRoot|MaxAuthTries)" /etc/ssh/sshd_config

5. Deliverables Summary

📄 Files to Submit

  • IAM Design Document (users, groups, roles table)
  • /etc/sudoers.d/abc-retail (sudo policies)
  • SSH public key (abc-retail-key.pub)
  • HashiCorp Vault setup commands & output
  • GPG key ID and encryption test output
  • /etc/audit/rules.d/ audit configuration
  • security-audit.sh script
  • Security Hardening Checklist (completed)
  • Screenshot: Vault UI showing stored secrets paths

✅ Verification Checklist

  • 4 non-root users created with correct groups
  • Sudo policies tested (allowed & denied)
  • SSH key pair generated and working
  • Password authentication disabled in sshd_config
  • Key-based login works from host machine
  • Vault running and secrets stored for all services
  • Backup script retrieves password from Vault
  • GPG key pair created and file encryption tested
  • MariaDB SSL enabled and verified
  • Auditd installed and rules configured
  • Security audit script runs and generates report

6. Why We Did This & What It Accomplishes

Strategic Intent & Operational Impact

Why We Did This

  • Security breaches overwhelmingly exploit weak credentials and excessive permissions — not sophisticated technical exploits. A developer with root access to the database server who accidentally runs a destructive command causes as much damage as a hacker. The principle of Least Privilege directly addresses this risk.
  • SSH key-based authentication is the industry standard for server access — every cloud provider, DevOps team, and enterprise uses it. Understanding how to generate keys, distribute public keys, and protect private keys is a foundational skill.
  • HashiCorp Vault solves a problem every organization faces: how to securely share credentials between applications and team members without exposing them in code or config files. Vault is used by thousands of companies including Capital One, Barclays, and Cisco.
  • Audit logs are required for regulatory compliance (GDPR requires you to know who accessed personal data, PCI-DSS requires logging all access to cardholder data). Without audit logs, you cannot prove compliance — or prove what happened during a security incident.

What This Accomplishes

  • ABC Retail now has an enterprise-grade security posture with IAM, MFA-equivalent access, secrets management, encryption, and audit logging — the complete security stack required for handling customer personal data and payment information.
  • The security architecture you designed and implemented is directly portable to cloud IAM: the Linux user/group concepts map to AWS IAM Users/Groups, the sudo policies map to IAM Policies, and Vault directly integrates with AWS Secrets Manager via sync plugins.
  • Your security implementation demonstrates security engineering skills valued in Cloud Security Engineer, Cloud DevOps Engineer, and DevSecOps roles — where security is built into infrastructure from the start rather than added as an afterthought.