ISO 27001 Implementation Guide: Building an Information Security Management System
ISO 27001 provides a framework for establishing, implementing, maintaining, and continually improving an Information Security Management System (ISMS). This guide provides practical implementation guidance for technology organizations.
ISMS Scope and Context
Defining ISMS Scope
# isms_scope.yaml
isms_scope:
organization:
name: "Example Technology Inc."
locations:
- name: "Headquarters"
address: "123 Tech Street, San Francisco, CA"
type: "office"
- name: "Cloud Infrastructure"
provider: "AWS"
regions: ["us-east-1", "eu-west-1"]
type: "cloud"
included_services:
- name: "SaaS Platform"
description: "Customer-facing web application"
data_classification: "confidential"
- name: "API Gateway"
description: "API services for integrations"
data_classification: "confidential"
- name: "Data Analytics"
description: "Internal analytics platform"
data_classification: "internal"
excluded:
- name: "Marketing Website"
justification: "No customer data processed"
- name: "Sales Demo Environment"
justification: "Uses synthetic data only"
interfaces:
external:
- "Customer integrations via API"
- "Third-party SaaS tools"
- "Cloud service providers"
internal:
- "Corporate network"
- "Development environments"
interested_parties:
- party: "Customers"
requirements:
- "Data protection"
- "Service availability"
- "Compliance certifications"
- party: "Regulators"
requirements:
- "GDPR compliance"
- "Industry regulations"
- party: "Employees"
requirements:
- "Clear security policies"
- "Security awareness training"
- party: "Shareholders"
requirements:
- "Risk management"
- "Business continuity"Risk Assessment
Risk Assessment Framework
# risk_assessment.py
from dataclasses import dataclass
from typing import List, Dict, Optional
from enum import Enum
from datetime import datetime
class Likelihood(Enum):
RARE = 1
UNLIKELY = 2
POSSIBLE = 3
LIKELY = 4
ALMOST_CERTAIN = 5
class Impact(Enum):
NEGLIGIBLE = 1
MINOR = 2
MODERATE = 3
MAJOR = 4
CATASTROPHIC = 5
@dataclass
class Asset:
"""Information asset."""
asset_id: str
name: str
description: str
owner: str
classification: str
value: int # 1-5 scale
location: str
@dataclass
class Threat:
"""Threat to information assets."""
threat_id: str
name: str
description: str
source: str # internal, external, environmental
likelihood: Likelihood
@dataclass
class Vulnerability:
"""Vulnerability in controls."""
vuln_id: str
name: str
description: str
affected_assets: List[str]
severity: int # 1-5 scale
@dataclass
class Risk:
"""Information security risk."""
risk_id: str
name: str
description: str
asset: Asset
threat: Threat
vulnerability: Vulnerability
likelihood: Likelihood
impact: Impact
inherent_risk_score: float
existing_controls: List[str]
residual_risk_score: float
risk_owner: str
treatment: str # accept, mitigate, transfer, avoid
treatment_plan: Optional[str]
class RiskAssessmentFramework:
"""ISO 27001 risk assessment framework."""
def __init__(self):
self.assets: Dict[str, Asset] = {}
self.threats: Dict[str, Threat] = {}
self.vulnerabilities: Dict[str, Vulnerability] = {}
self.risks: Dict[str, Risk] = {}
self.risk_acceptance_threshold = 12
def register_asset(self, asset: Asset):
"""Register an information asset."""
self.assets[asset.asset_id] = asset
def identify_threat(self, threat: Threat):
"""Identify a threat."""
self.threats[threat.threat_id] = threat
def identify_vulnerability(self, vulnerability: Vulnerability):
"""Identify a vulnerability."""
self.vulnerabilities[vulnerability.vuln_id] = vulnerability
def assess_risk(
self,
asset_id: str,
threat_id: str,
vuln_id: str,
impact: Impact,
existing_controls: List[str],
control_effectiveness: float = 0.5
) -> Risk:
"""Assess a specific risk scenario."""
asset = self.assets[asset_id]
threat = self.threats[threat_id]
vulnerability = self.vulnerabilities[vuln_id]
# Calculate inherent risk
inherent_risk = self._calculate_risk_score(
threat.likelihood, impact, asset.value
)
# Calculate residual risk (after controls)
residual_risk = inherent_risk * (1 - control_effectiveness)
# Determine treatment
treatment = self._determine_treatment(residual_risk)
risk = Risk(
risk_id=f"R-{len(self.risks) + 1:04d}",
name=f"{threat.name} to {asset.name}",
description=f"Risk of {threat.description} exploiting {vulnerability.name}",
asset=asset,
threat=threat,
vulnerability=vulnerability,
likelihood=threat.likelihood,
impact=impact,
inherent_risk_score=inherent_risk,
existing_controls=existing_controls,
residual_risk_score=residual_risk,
risk_owner=asset.owner,
treatment=treatment,
treatment_plan=None
)
self.risks[risk.risk_id] = risk
return risk
def _calculate_risk_score(
self,
likelihood: Likelihood,
impact: Impact,
asset_value: int
) -> float:
"""Calculate risk score."""
base_score = likelihood.value * impact.value
weighted_score = base_score * (asset_value / 5)
return round(weighted_score, 2)
def _determine_treatment(self, risk_score: float) -> str:
"""Determine risk treatment approach."""
if risk_score <= 4:
return 'accept'
elif risk_score <= 8:
return 'mitigate'
elif risk_score <= 16:
return 'mitigate' # Higher priority
else:
return 'avoid'
def generate_risk_register(self) -> List[Dict]:
"""Generate risk register."""
register = []
for risk in sorted(
self.risks.values(),
key=lambda r: r.residual_risk_score,
reverse=True
):
register.append({
'risk_id': risk.risk_id,
'name': risk.name,
'asset': risk.asset.name,
'threat': risk.threat.name,
'vulnerability': risk.vulnerability.name,
'likelihood': risk.likelihood.name,
'impact': risk.impact.name,
'inherent_risk': risk.inherent_risk_score,
'existing_controls': risk.existing_controls,
'residual_risk': risk.residual_risk_score,
'risk_owner': risk.risk_owner,
'treatment': risk.treatment,
'above_threshold': risk.residual_risk_score > self.risk_acceptance_threshold
})
return register
def generate_statement_of_applicability(
self,
controls: List[Dict]
) -> List[Dict]:
"""Generate Statement of Applicability."""
soa = []
for control in controls:
applicable_risks = [
r for r in self.risks.values()
if control['id'] in r.existing_controls or
control['id'] in (r.treatment_plan or '')
]
soa.append({
'control_id': control['id'],
'control_name': control['name'],
'applicable': len(applicable_risks) > 0,
'justification': control.get('justification', ''),
'implementation_status': control.get('status', 'not_implemented'),
'related_risks': [r.risk_id for r in applicable_risks]
})
return soaControl Implementation
Annex A Control Framework
# control_implementation.py
from dataclasses import dataclass
from typing import List, Dict, Optional
from enum import Enum
from datetime import datetime
class ControlStatus(Enum):
NOT_IMPLEMENTED = "not_implemented"
PARTIALLY_IMPLEMENTED = "partially_implemented"
IMPLEMENTED = "implemented"
NOT_APPLICABLE = "not_applicable"
@dataclass
class Control:
"""ISO 27001 Annex A control."""
control_id: str
category: str
name: str
description: str
status: ControlStatus
implementation_evidence: List[str]
owner: str
review_date: Optional[datetime]
class AnnexAControls:
"""ISO 27001:2022 Annex A control framework."""
CONTROL_CATEGORIES = {
'A.5': 'Organizational controls',
'A.6': 'People controls',
'A.7': 'Physical controls',
'A.8': 'Technological controls'
}
def __init__(self):
self.controls = self._initialize_controls()
def _initialize_controls(self) -> Dict[str, Control]:
"""Initialize Annex A controls."""
controls = {}
# A.5 Organizational controls
organizational = [
('A.5.1', 'Policies for information security'),
('A.5.2', 'Information security roles and responsibilities'),
('A.5.3', 'Segregation of duties'),
('A.5.4', 'Management responsibilities'),
('A.5.5', 'Contact with authorities'),
('A.5.6', 'Contact with special interest groups'),
('A.5.7', 'Threat intelligence'),
('A.5.8', 'Information security in project management'),
('A.5.9', 'Inventory of information and other associated assets'),
('A.5.10', 'Acceptable use of information and other associated assets'),
('A.5.11', 'Return of assets'),
('A.5.12', 'Classification of information'),
('A.5.13', 'Labelling of information'),
('A.5.14', 'Information transfer'),
('A.5.15', 'Access control'),
('A.5.16', 'Identity management'),
('A.5.17', 'Authentication information'),
('A.5.18', 'Access rights'),
('A.5.19', 'Information security in supplier relationships'),
('A.5.20', 'Addressing information security within supplier agreements'),
('A.5.21', 'Managing information security in the ICT supply chain'),
('A.5.22', 'Monitoring, review and change management of supplier services'),
('A.5.23', 'Information security for use of cloud services'),
('A.5.24', 'Information security incident management planning and preparation'),
('A.5.25', 'Assessment and decision on information security events'),
('A.5.26', 'Response to information security incidents'),
('A.5.27', 'Learning from information security incidents'),
('A.5.28', 'Collection of evidence'),
('A.5.29', 'Information security during disruption'),
('A.5.30', 'ICT readiness for business continuity'),
('A.5.31', 'Legal, statutory, regulatory and contractual requirements'),
('A.5.32', 'Intellectual property rights'),
('A.5.33', 'Protection of records'),
('A.5.34', 'Privacy and protection of PII'),
('A.5.35', 'Independent review of information security'),
('A.5.36', 'Compliance with policies, rules and standards for information security'),
('A.5.37', 'Documented operating procedures'),
]
for control_id, name in organizational:
controls[control_id] = Control(
control_id=control_id,
category='Organizational',
name=name,
description='',
status=ControlStatus.NOT_IMPLEMENTED,
implementation_evidence=[],
owner='',
review_date=None
)
# A.6 People controls
people = [
('A.6.1', 'Screening'),
('A.6.2', 'Terms and conditions of employment'),
('A.6.3', 'Information security awareness, education and training'),
('A.6.4', 'Disciplinary process'),
('A.6.5', 'Responsibilities after termination or change of employment'),
('A.6.6', 'Confidentiality or non-disclosure agreements'),
('A.6.7', 'Remote working'),
('A.6.8', 'Information security event reporting'),
]
for control_id, name in people:
controls[control_id] = Control(
control_id=control_id,
category='People',
name=name,
description='',
status=ControlStatus.NOT_IMPLEMENTED,
implementation_evidence=[],
owner='',
review_date=None
)
# A.7 Physical controls
physical = [
('A.7.1', 'Physical security perimeters'),
('A.7.2', 'Physical entry'),
('A.7.3', 'Securing offices, rooms and facilities'),
('A.7.4', 'Physical security monitoring'),
('A.7.5', 'Protecting against physical and environmental threats'),
('A.7.6', 'Working in secure areas'),
('A.7.7', 'Clear desk and clear screen'),
('A.7.8', 'Equipment siting and protection'),
('A.7.9', 'Security of assets off-premises'),
('A.7.10', 'Storage media'),
('A.7.11', 'Supporting utilities'),
('A.7.12', 'Cabling security'),
('A.7.13', 'Equipment maintenance'),
('A.7.14', 'Secure disposal or re-use of equipment'),
]
for control_id, name in physical:
controls[control_id] = Control(
control_id=control_id,
category='Physical',
name=name,
description='',
status=ControlStatus.NOT_IMPLEMENTED,
implementation_evidence=[],
owner='',
review_date=None
)
# A.8 Technological controls
technological = [
('A.8.1', 'User endpoint devices'),
('A.8.2', 'Privileged access rights'),
('A.8.3', 'Information access restriction'),
('A.8.4', 'Access to source code'),
('A.8.5', 'Secure authentication'),
('A.8.6', 'Capacity management'),
('A.8.7', 'Protection against malware'),
('A.8.8', 'Management of technical vulnerabilities'),
('A.8.9', 'Configuration management'),
('A.8.10', 'Information deletion'),
('A.8.11', 'Data masking'),
('A.8.12', 'Data leakage prevention'),
('A.8.13', 'Information backup'),
('A.8.14', 'Redundancy of information processing facilities'),
('A.8.15', 'Logging'),
('A.8.16', 'Monitoring activities'),
('A.8.17', 'Clock synchronization'),
('A.8.18', 'Use of privileged utility programs'),
('A.8.19', 'Installation of software on operational systems'),
('A.8.20', 'Networks security'),
('A.8.21', 'Security of network services'),
('A.8.22', 'Segregation of networks'),
('A.8.23', 'Web filtering'),
('A.8.24', 'Use of cryptography'),
('A.8.25', 'Secure development life cycle'),
('A.8.26', 'Application security requirements'),
('A.8.27', 'Secure system architecture and engineering principles'),
('A.8.28', 'Secure coding'),
('A.8.29', 'Security testing in development and acceptance'),
('A.8.30', 'Outsourced development'),
('A.8.31', 'Separation of development, test and production environments'),
('A.8.32', 'Change management'),
('A.8.33', 'Test information'),
('A.8.34', 'Protection of information systems during audit testing'),
]
for control_id, name in technological:
controls[control_id] = Control(
control_id=control_id,
category='Technological',
name=name,
description='',
status=ControlStatus.NOT_IMPLEMENTED,
implementation_evidence=[],
owner='',
review_date=None
)
return controls
def update_control_status(
self,
control_id: str,
status: ControlStatus,
evidence: List[str],
owner: str
):
"""Update control implementation status."""
if control_id in self.controls:
control = self.controls[control_id]
control.status = status
control.implementation_evidence = evidence
control.owner = owner
control.review_date = datetime.utcnow()
def generate_control_report(self) -> Dict:
"""Generate control implementation report."""
total = len(self.controls)
by_status = {status: 0 for status in ControlStatus}
by_category = {}
for control in self.controls.values():
by_status[control.status] += 1
if control.category not in by_category:
by_category[control.category] = {'total': 0, 'implemented': 0}
by_category[control.category]['total'] += 1
if control.status == ControlStatus.IMPLEMENTED:
by_category[control.category]['implemented'] += 1
return {
'total_controls': total,
'by_status': {s.value: c for s, c in by_status.items()},
'by_category': by_category,
'implementation_percentage': (
by_status[ControlStatus.IMPLEMENTED] / total * 100
),
'controls_needing_attention': [
{
'id': c.control_id,
'name': c.name,
'status': c.status.value
}
for c in self.controls.values()
if c.status in [
ControlStatus.NOT_IMPLEMENTED,
ControlStatus.PARTIALLY_IMPLEMENTED
]
]
}Documentation Requirements
Policy Document Structure
# documentation_structure.yaml
isms_documentation:
level_1_policies:
- name: "Information Security Policy"
owner: "CISO"
review_frequency: "annual"
approval: "Board"
level_2_standards:
- name: "Access Control Standard"
related_controls: ["A.5.15", "A.5.16", "A.5.17", "A.5.18"]
- name: "Cryptography Standard"
related_controls: ["A.8.24"]
- name: "Network Security Standard"
related_controls: ["A.8.20", "A.8.21", "A.8.22"]
- name: "Secure Development Standard"
related_controls: ["A.8.25", "A.8.26", "A.8.27", "A.8.28"]
level_3_procedures:
- name: "User Access Management Procedure"
- name: "Incident Response Procedure"
- name: "Change Management Procedure"
- name: "Backup and Recovery Procedure"
- name: "Vulnerability Management Procedure"
level_4_records:
- name: "Risk Assessment Records"
- name: "Audit Logs"
- name: "Training Records"
- name: "Incident Records"
- name: "Change Records"
mandatory_documents:
- "ISMS Scope"
- "Information Security Policy"
- "Risk Assessment Methodology"
- "Risk Assessment Report"
- "Risk Treatment Plan"
- "Statement of Applicability"
- "Information Security Objectives"
- "Competence Evidence"
- "Documented Operating Procedures"
- "Results of Monitoring and Measurement"
- "Internal Audit Program and Results"
- "Management Review Minutes"
- "Nonconformities and Corrective Actions"Internal Audit Program
Audit Planning and Execution
# internal_audit.py
from dataclasses import dataclass
from typing import List, Dict, Optional
from datetime import datetime, timedelta
from enum import Enum
class FindingSeverity(Enum):
MAJOR_NC = "major_nonconformity"
MINOR_NC = "minor_nonconformity"
OBSERVATION = "observation"
OPPORTUNITY = "opportunity_for_improvement"
@dataclass
class AuditFinding:
"""Internal audit finding."""
finding_id: str
audit_id: str
control_id: str
severity: FindingSeverity
description: str
evidence: str
root_cause: Optional[str]
corrective_action: Optional[str]
due_date: Optional[datetime]
status: str # open, in_progress, closed, verified
class InternalAuditProgram:
"""ISO 27001 internal audit program."""
def __init__(self):
self.audits = {}
self.findings = {}
def create_audit_plan(
self,
audit_year: int,
controls: List[str]
) -> Dict:
"""Create annual audit plan."""
# Ensure all controls are audited at least once per year
audits_per_year = 4 # Quarterly audits
controls_per_audit = len(controls) // audits_per_year + 1
plan = {
'year': audit_year,
'audits': []
}
for quarter in range(1, 5):
start_idx = (quarter - 1) * controls_per_audit
end_idx = min(start_idx + controls_per_audit, len(controls))
audit_month = (quarter - 1) * 3 + 2 # Feb, May, Aug, Nov
plan['audits'].append({
'audit_id': f'AUDIT-{audit_year}-Q{quarter}',
'quarter': quarter,
'scheduled_date': datetime(audit_year, audit_month, 15),
'controls_in_scope': controls[start_idx:end_idx],
'status': 'planned'
})
return plan
def record_finding(
self,
audit_id: str,
control_id: str,
severity: FindingSeverity,
description: str,
evidence: str
) -> AuditFinding:
"""Record audit finding."""
finding = AuditFinding(
finding_id=f'F-{len(self.findings) + 1:04d}',
audit_id=audit_id,
control_id=control_id,
severity=severity,
description=description,
evidence=evidence,
root_cause=None,
corrective_action=None,
due_date=self._calculate_due_date(severity),
status='open'
)
self.findings[finding.finding_id] = finding
return finding
def _calculate_due_date(self, severity: FindingSeverity) -> datetime:
"""Calculate corrective action due date based on severity."""
days_map = {
FindingSeverity.MAJOR_NC: 30,
FindingSeverity.MINOR_NC: 60,
FindingSeverity.OBSERVATION: 90,
FindingSeverity.OPPORTUNITY: 120
}
return datetime.utcnow() + timedelta(days=days_map[severity])
def assign_corrective_action(
self,
finding_id: str,
root_cause: str,
corrective_action: str
):
"""Assign corrective action to finding."""
finding = self.findings.get(finding_id)
if finding:
finding.root_cause = root_cause
finding.corrective_action = corrective_action
finding.status = 'in_progress'
def verify_closure(self, finding_id: str, verification_evidence: str) -> bool:
"""Verify corrective action and close finding."""
finding = self.findings.get(finding_id)
if finding and finding.status == 'in_progress':
finding.status = 'verified'
return True
return False
def generate_audit_report(self, audit_id: str) -> Dict:
"""Generate audit report."""
audit_findings = [
f for f in self.findings.values()
if f.audit_id == audit_id
]
return {
'audit_id': audit_id,
'total_findings': len(audit_findings),
'by_severity': {
severity.value: len([
f for f in audit_findings
if f.severity == severity
])
for severity in FindingSeverity
},
'findings': [
{
'id': f.finding_id,
'control': f.control_id,
'severity': f.severity.value,
'description': f.description,
'status': f.status
}
for f in audit_findings
]
}Certification Preparation
Readiness Assessment Checklist
# certification_readiness.py
from dataclasses import dataclass
from typing import List, Dict
from datetime import datetime
@dataclass
class ReadinessItem:
"""Certification readiness checklist item."""
item_id: str
category: str
requirement: str
status: str # not_started, in_progress, complete
evidence: List[str]
notes: str
class CertificationReadiness:
"""ISO 27001 certification readiness assessment."""
def __init__(self):
self.checklist = self._initialize_checklist()
def _initialize_checklist(self) -> List[ReadinessItem]:
"""Initialize readiness checklist."""
items = [
# Context and Leadership
('CTX-01', 'Context', 'ISMS scope document defined and approved'),
('CTX-02', 'Context', 'Interested parties identified with requirements'),
('CTX-03', 'Context', 'Context of organization documented'),
('LDR-01', 'Leadership', 'Information security policy approved by management'),
('LDR-02', 'Leadership', 'Roles and responsibilities assigned'),
('LDR-03', 'Leadership', 'Management commitment documented'),
# Planning
('PLN-01', 'Planning', 'Risk assessment methodology defined'),
('PLN-02', 'Planning', 'Risk assessment completed'),
('PLN-03', 'Planning', 'Risk treatment plan developed'),
('PLN-04', 'Planning', 'Statement of Applicability completed'),
('PLN-05', 'Planning', 'Information security objectives defined'),
# Support
('SUP-01', 'Support', 'Resources allocated'),
('SUP-02', 'Support', 'Competence requirements defined'),
('SUP-03', 'Support', 'Security awareness program implemented'),
('SUP-04', 'Support', 'Communication procedures established'),
('SUP-05', 'Support', 'Document control implemented'),
# Operation
('OPR-01', 'Operation', 'Operational planning and control implemented'),
('OPR-02', 'Operation', 'Risk treatment implemented'),
('OPR-03', 'Operation', 'Controls from SoA implemented'),
# Performance Evaluation
('PER-01', 'Performance', 'Monitoring and measurement defined'),
('PER-02', 'Performance', 'Internal audit program established'),
('PER-03', 'Performance', 'At least one audit cycle completed'),
('PER-04', 'Performance', 'Management review conducted'),
# Improvement
('IMP-01', 'Improvement', 'Nonconformity process defined'),
('IMP-02', 'Improvement', 'Corrective actions tracked'),
('IMP-03', 'Improvement', 'Continual improvement process documented'),
]
return [
ReadinessItem(
item_id=item_id,
category=category,
requirement=requirement,
status='not_started',
evidence=[],
notes=''
)
for item_id, category, requirement in items
]
def assess_readiness(self) -> Dict:
"""Assess overall certification readiness."""
total = len(self.checklist)
complete = len([i for i in self.checklist if i.status == 'complete'])
in_progress = len([i for i in self.checklist if i.status == 'in_progress'])
by_category = {}
for item in self.checklist:
if item.category not in by_category:
by_category[item.category] = {'total': 0, 'complete': 0}
by_category[item.category]['total'] += 1
if item.status == 'complete':
by_category[item.category]['complete'] += 1
readiness_percentage = (complete / total) * 100
return {
'assessment_date': datetime.utcnow().isoformat(),
'overall_readiness': readiness_percentage,
'total_items': total,
'complete': complete,
'in_progress': in_progress,
'not_started': total - complete - in_progress,
'by_category': {
cat: {
'percentage': (data['complete'] / data['total']) * 100,
**data
}
for cat, data in by_category.items()
},
'gaps': [
{
'id': item.item_id,
'category': item.category,
'requirement': item.requirement
}
for item in self.checklist
if item.status != 'complete'
],
'ready_for_stage_1': readiness_percentage >= 80,
'ready_for_stage_2': readiness_percentage >= 95
}Conclusion
ISO 27001 implementation requires systematic attention to:
- Scope Definition - Clear boundaries and context
- Risk Assessment - Comprehensive threat and vulnerability analysis
- Control Implementation - Annex A controls tailored to identified risks
- Documentation - Policies, procedures, and records
- Internal Auditing - Regular compliance verification
- Continual Improvement - Ongoing enhancement of the ISMS
Successful certification depends on demonstrating both implementation effectiveness and management commitment to information security.