Cloud Security Guide — Shared Responsibility, IAM, KMS, and Zero Trust
Cloud security is the practice of protecting data, applications, and infrastructure in cloud environments through a shared responsibility model where the provider secures the infrastructure and the customer secures their data and configurations.
What You’ll Learn
By the end of this tutorial, you’ll understand the shared responsibility model, IAM roles and policies, KMS for encryption, security groups and WAF, Zero Trust principles in the cloud, CIS benchmarks, and compliance frameworks (SOC2, HIPAA, GDPR).
Why Cloud Security Matters
Cloud security misconfigurations are the #1 cause of data breaches. Open S3 buckets, exposed IAM keys, and unpatched vulnerabilities are exploited daily. With over 90% of enterprises using cloud services in 2026, understanding how to secure cloud environments is essential for every engineer. DodaTech’s Durga Antivirus Pro cloud infrastructure follows CIS benchmarks and SOC2 compliance.
Cloud Security Learning Path
flowchart LR
A[Cloud Basics] --> B[Cloud Security]
B --> C{You Are Here}
C --> D[Shared Responsibility]
C --> E[IAM]
C --> F[Zero Trust]
D --> G[Provider vs Customer]
E --> H[Roles & Policies]
E --> I[KMS Encryption]
What Is Cloud Security?
Think of cloud security like securing an apartment building you don’t own. The building owner (cloud provider) handles outer walls, roof, locks on main doors, fire alarms in hallways, and security cameras at entrances. You (the tenant) are responsible for locking your apartment door, setting your alarm, not sharing your keys, and not leaving valuables in plain sight.
The shared responsibility model defines exactly where the provider’s responsibility ends and yours begins.
Shared Responsibility Model
flowchart TB
subgraph "Customer Responsibility"
direction TB
C1[Data Classification & Encryption]
C2[Platform & IAM]
C3[OS, Network & Firewall Config]
C4[Client-side Encryption]
end
subgraph "Provider Responsibility"
direction TB
P1[Physical Security]
P2[Hardware & Networking]
P3[Virtualization Layer]
P4[Global Infrastructure]
end
C1 --> C2 --> C3 --> C4
P1 --> P2 --> P3 --> P4
| Layer | Provider Responsible | Customer Responsible |
|---|---|---|
| Physical | Data centers, power, cooling | Nothing |
| Hardware | Servers, storage, networking | Nothing |
| Virtualization | Hypervisor, host OS | Guest OS configuration |
| Compute | Host maintenance | OS patching, app security |
| Data | Storage infrastructure | Encryption, access, classification |
| Network | Physical network | Security groups, ACLs, WAF |
IAM — Identity and Access Management
IAM controls WHO can do WHAT on WHICH resources.
# iam_policy_simulator.py
# Simulate IAM policy evaluation
import json
class IAMPolicyEngine:
def __init__(self):
self.policies = []
def add_policy(self, name, effect, actions, resources, conditions=None):
self.policies.append({
"name": name,
"effect": effect,
"actions": actions,
"resources": resources,
"conditions": conditions or {},
})
def evaluate(self, principal, action, resource, context=None):
"""Evaluate if an action is allowed."""
matching = []
for policy in self.policies:
if action in policy["actions"] or "*" in policy["actions"]:
if any(resource.startswith(r) or r == "*" for r in policy["resources"]):
matching.append(policy)
# Deny takes precedence over Allow
for policy in matching:
if policy["effect"] == "Deny":
return "DENY"
for policy in matching:
if policy["effect"] == "Allow":
return "ALLOW"
return "DENY (implicit)"
print("=== IAM Policy Evaluation ===\n")
engine = IAMPolicyEngine()
engine.add_policy("AdminAccess", "Allow", ["*"], ["*"])
engine.add_policy("S3ReadOnly", "Allow", ["s3:Get*", "s3:List*"], ["arn:aws:s3:::dodatech-data"])
engine.add_policy("ExplicitDeny", "Deny", ["s3:Delete*"], ["arn:aws:s3:::*"])
scenarios = [
("admin@dodatech", "s3:GetObject", "arn:aws:s3:::dodatech-data/report.pdf"),
("analyst@dodatech", "s3:GetObject", "arn:aws:s3:::dodatech-data/report.pdf"),
("analyst@dodatech", "s3:DeleteObject", "arn:aws:s3:::dodatech-data/report.pdf"),
("intern@dodatech", "s3:PutObject", "arn:aws:s3:::other-bucket/file.txt"),
]
print(f"{'Principal':<20} {'Action':<20} {'Resource':<45} {'Result'}")
print("-" * 100)
for principal, action, resource in scenarios:
result = engine.evaluate(principal, action, resource)
print(f"{principal:<20} {action:<20} {resource:<45} {result}")Expected output:
=== IAM Policy Evaluation ===
Principal Action Resource Result
----------------------------------------------------------------------------------------------------
admin@dodatech s3:GetObject arn:aws:s3:::dodatech-data/report.pdf ALLOW
analyst@dodatech s3:GetObject arn:aws:s3:::dodatech-data/report.pdf ALLOW
analyst@dodatech s3:DeleteObject arn:aws:s3:::dodatech-data/report.pdf DENY
intern@dodatech s3:PutObject arn:aws:s3:::other-bucket/file.txt DENY (implicit)KMS — Key Management Service
KMS manages encryption keys for data at rest and in transit.
# kms_demo.py
# Simulate KMS envelope encryption
import os
import json
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2
class KMS:
"""Simulated KMS for learning (simplified)."""
def __init__(self):
self.master_keys = {}
self.data_keys = {}
def create_key(self, key_id, description=""):
self.master_keys[key_id] = {
"id": key_id,
"description": description,
"created": "2026-06-15",
"enabled": True,
}
print(f"[KMS] Created master key: {key_id}")
return key_id
def generate_data_key(self, key_id):
"""Generate a data key encrypted under the master key."""
data_key = Fernet.generate_key()
self.data_keys[key_id] = data_key
print(f"[KMS] Generated data key for {key_id}")
return data_key
def encrypt(self, key_id, plaintext):
if key_id not in self.data_keys:
raise ValueError(f"Data key for {key_id} not found")
f = Fernet(self.data_keys[key_id])
ciphertext = f.encrypt(plaintext.encode())
print(f"[KMS] Encrypted {len(plaintext)} bytes → {len(ciphertext)} bytes")
return ciphertext
def decrypt(self, key_id, ciphertext):
if key_id not in self.data_keys:
raise ValueError(f"Data key for {key_id} not found")
f = Fernet(self.data_keys[key_id])
plaintext = f.decrypt(ciphertext).decode()
print(f"[KMS] Decrypted {len(ciphertext)} bytes → {len(plaintext)} bytes")
return plaintext
kms = KMS()
key = kms.create_key("dodatech-app-key", "App secrets encryption")
kms.generate_data_key(key)
secret = "Password: SuperSecret123!"
encrypted = kms.encrypt(key, secret)
decrypted = kms.decrypt(key, encrypted)
print(f"\nOriginal: {secret}")
print(f"Decrypted: {decrypted}")
print(f"Match: {secret == decrypted}")Expected output:
[KMS] Created master key: dodatech-app-key
[KMS] Generated data key for dodatech-app-key
[KMS] Encrypted 30 bytes → 108 bytes
[KMS] Decrypted 108 bytes → 30 bytes
Original: Password: SuperSecret123!
Decrypted: Password: SuperSecret123!
Match: TrueZero Trust in the Cloud
Zero Trust assumes no entity is trusted by default — every request must be authenticated, authorized, and validated.
| Principle | Cloud Implementation |
|---|---|
| Never trust, always verify | IAM policies, API keys, MFA on every request |
| Least privilege | Grant minimum permissions needed, use resource-based policies |
| Assume breach | Network segmentation, micro-segmentation, encryption everywhere |
| Continuous verification | CloudTrail logging, anomaly detection, GuardDuty |
Security Groups and WAF
# security_groups.py
# Simulate security group evaluation
class SecurityGroup:
def __init__(self, name):
self.name = name
self.inbound_rules = []
self.outbound_rules = []
def allow_inbound(self, protocol, port, source, description=""):
self.inbound_rules.append({"protocol": protocol, "port": port, "source": source, "desc": description})
def allow_outbound(self, protocol, port, destination, description=""):
self.outbound_rules.append({"protocol": protocol, "port": port, "destination": destination, "desc": description})
def check_inbound(self, protocol, port, source_ip):
for rule in self.inbound_rules:
if rule["protocol"] in (protocol, "-1") and \
(rule["port"] == port or rule["port"] == "ALL") and \
(rule["source"] == "0.0.0.0/0" or source_ip.startswith(rule["source"].replace("0.0.0.0/0", "").rstrip(".0"))):
return "ALLOW", rule["desc"]
return "DENY", "No matching rule"
web_sg = SecurityGroup("web-server-sg")
web_sg.allow_inbound("tcp", 80, "0.0.0.0/0", "HTTP traffic")
web_sg.allow_inbound("tcp", 443, "0.0.0.0/0", "HTTPS traffic")
web_sg.allow_inbound("tcp", 22, "10.0.0.0/8", "SSH from internal")
web_sg.allow_outbound("-1", "ALL", "0.0.0.0/0", "All outbound")
print("=== Security Group Rules: web-server-sg ===")
for rule in web_sg.inbound_rules:
print(f" {rule['protocol']:<5} {rule['port']:<8} {rule['source']:<20} {rule['desc']}")
print("\n=== Inbound Traffic Checks ===")
checks = [("tcp", 443, "203.0.113.5"), ("tcp", 22, "203.0.113.5"), ("tcp", 22, "10.0.1.50"), ("udp", 53, "8.8.8.8")]
for protocol, port, ip in checks:
result, reason = web_sg.check_inbound(protocol, port, ip)
print(f" {protocol.upper()} {port} from {ip:<20} → {result:<6} ({reason})")Expected output:
=== Security Group Rules: web-server-sg ===
tcp 80 0.0.0.0/0 HTTP traffic
tcp 443 0.0.0.0/0 HTTPS traffic
tcp 22 10.0.0.0/8 SSH from internal
=== Inbound Traffic Checks ===
TCP 443 from 203.0.113.5 → ALLOW (HTTPS traffic)
TCP 22 from 203.0.113.5 → DENY (No matching rule)
TCP 22 from 10.0.1.50 → ALLOW (SSH from internal)
UDP 53 from 8.8.8.8 → DENY (No matching rule)Compliance Frameworks
| Framework | Focus | Key Requirements |
|---|---|---|
| SOC 2 | Service organization controls | Encryption, access control, monitoring, incident response |
| HIPAA | Healthcare data privacy | BAA agreements, audit logs, encryption, access controls |
| GDPR | EU data protection | Data classification, right to deletion, consent management |
| PCI DSS | Payment card data | Network segmentation, encryption, quarterly scans |
| ISO 27001 | Information security management | Risk assessment, security policy, continuous improvement |
Common Cloud Security Mistakes
1. Overly Permissive IAM Policies
Using "Action": "*" on "Resource": "*" grants full admin access. Always follow least privilege — define specific actions and resources.
2. Exposed Access Keys
Hard-coded AWS_ACCESS_KEY_ID in GitHub repos, config files, or environment variables. Use IAM roles for EC2/Lambda and Secrets Manager for app secrets.
3. Open Security Groups
Security groups allowing 0.0.0.0/0 on SSH (port 22) or databases (3306, 5432). Restrict to specific IPs or VPC ranges.
4. No Encryption at Rest
S3 buckets, EBS volumes, and RDS databases without encryption expose data if storage is compromised. Enable default encryption everywhere.
5. Disabled Logging and Monitoring
Without CloudTrail (AWS), Activity Logs (Azure), or Cloud Audit (GCP), you can’t detect breaches. Enable logging from day one.
6. Not Using Multi-Factor Authentication
Root accounts and IAM users without MFA are a single password away from compromise. Enforce MFA for all users.
Practice Questions
1. What is the shared responsibility model in cloud security?
The cloud provider secures the infrastructure (physical security, hardware, network). The customer secures everything they deploy (data, IAM, OS config, app security). The boundary varies by service type (IaaS, PaaS, SaaS).
2. What is the principle of least privilege?
Grant only the minimum permissions needed for a user or service to perform their function. Never use wildcard permissions unless absolutely necessary.
3. How does KMS help secure cloud data?
KMS manages encryption keys centrally. It enables envelope encryption (master key encrypts data keys, which encrypt data), automatic key rotation, and access control through IAM.
4. What is Zero Trust security?
An approach where no entity is trusted by default. Every request must be authenticated, authorized, and validated regardless of network location. “Never trust, always verify.”
5. Challenge: Design a security architecture for a multi-tier web application on AWS with web servers, application servers, and a managed database, following least privilege.
Three security groups: (1) Web SG: allow 80/443 from 0.0.0.0/0, 22 from corp VPN only. (2) App SG: allow from Web SG only. (3) DB SG: allow 3306 from App SG only. IAM roles: EC2 gets S3 read role, RDS gets KMS decrypt role. Enable CloudTrail, GuardDuty, and S3 bucket logging.
Mini Project: Cloud Security Audit
# cloud_security_audit.py
# Perform a basic security audit on a simulated cloud environment
import json
def audit_security_group(name, rules, checks):
findings = []
for protocol, port, source, description in rules:
if source == "0.0.0.0/0" and port in (22, 3389, 3306, 5432, 6379, 27017):
findings.append(f"HIGH: {name} allows public {description} ({protocol}/{port} from {source})")
elif source == "0.0.0.0/0" and port in checks.get("restricted_ports", []):
findings.append(f"MEDIUM: {name} allows public {description} ({protocol}/{port} from {source})")
return findings
def check_iam_policy(policy):
findings = []
if policy.get("Action") == "*" and policy.get("Resource") == "*":
findings.append("CRITICAL: IAM policy grants full admin access (*:* on *)")
if isinstance(policy.get("Action"), list) and "*" in policy["Action"]:
findings.append("HIGH: IAM policy uses wildcard Action")
return findings
audit_results = []
# Security group checks
sg_rules = [
("web-sg", 22, "0.0.0.0/0", "SSH"),
("web-sg", 443, "0.0.0.0/0", "HTTPS"),
("db-sg", 3306, "10.0.0.0/16", "MySQL"),
("admin-sg", 22, "203.0.113.0/24", "SSH Admin"),
("redis-sg", 6379, "0.0.0.0/0", "Redis"),
]
checks = {"restricted_ports": [22, 3389, 3306, 5432, 6379, 27017, 9200]}
audit_results.extend(audit_security_group("sg-rules", sg_rules, checks))
# IAM policy checks
iam_policies = [
{"name": "admin-policy", "Action": "*", "Resource": "*"},
{"name": "s3-readonly", "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": "arn:aws:s3:::my-bucket/*"},
{"name": "dev-policy", "Action": ["ec2:*", "s3:*", "lambda:*"], "Resource": "*"},
]
for policy in iam_policies:
audit_results.extend(check_iam_policy(policy))
print("=== Cloud Security Audit Report ===\n")
for finding in audit_results:
print(f" • {finding}")
print(f"\nTotal findings: {len(audit_results)}")Expected output:
=== Cloud Security Audit Report ===
• HIGH: sg-rules allows public SSH (tcp/22 from 0.0.0.0/0)
• HIGH: sg-rules allows public MySQL (tcp/3306 from 0.0.0.0/0)
• HIGH: sg-rules allows public Redis (tcp/6379 from 0.0.0.0/0)
• CRITICAL: IAM policy grants full admin access (*:* on *)
• HIGH: IAM policy uses wildcard Action
Total findings: 5Related Concepts
What’s Next
You now understand cloud security fundamentals! Next, learn cloud cost optimization to manage spending, and cloud monitoring for observability.
- Practice daily — Review your cloud account’s IAM policies and security groups
- Build a project — Set up CloudTrail + GuardDuty for your AWS account
- Explore related topics — Check out DevSecOps for security automation in CI/CD
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro