Trust Is Not a Control: ISO 27001 Compliance via GitHub

Trust Is Not a Control: ISO 27001 Compliance via GitHub

Every compliance audit eventually arrives at the same uncomfortable question: “Show me how you control changes to production systems.”

If your answer involves developers pushing directly to the main branch, running deployment scripts from their laptops, or “we have a process document somewhere,” you’re not demonstrating compliance—you’re demonstrating risk. ISO/IEC 27001 doesn’t accept “we trust our developers” as a control mechanism. It requires demonstrable, auditable, technically enforced change management.

Here’s what I’ve learned from teams navigating ISO 27001 certification: the ones who struggle aren’t lacking documentation. They’re lacking technical controls that make compliance violations impossible. The ones who succeed embed compliance directly into their development workflow using tools they already have—specifically, GitHub’s branch protection and pull request mechanisms.

This article examines how ISO 27001 Controls A.12.1 (Operational procedures and responsibilities) and A.14.2 (Security in development and support processes) translate into concrete GitHub configurations. Not theoretical compliance theater. Not checkbox exercises for auditors. Real technical controls that simultaneously improve code quality and satisfy audit requirements.

The Compliance Gap: What ISO 27001 Actually Requires

ISO 27001 Control A.12.1.2 (Change management) states clearly: “Changes to the organization, business processes, information processing facilities and systems that affect information security shall be controlled.”

Control A.14.2.2 (System change control procedures) gets more specific: “Changes to systems within the development lifecycle shall be controlled by the use of formal change control procedures.”

What does “controlled” mean in practical terms? It means you can demonstrate:

  1. Authorization: Who approved this change for production deployment?
  2. Review: Who verified this change meets security and quality standards?
  3. Testing: What evidence exists that this change was tested before production?
  4. Traceability: Can you trace any production code back to the specific change request that introduced it?
  5. Segregation: Are developers prevented from unilaterally deploying their own changes to production?
  6. Auditability: Can you reconstruct exactly what changed, when, and by whom?

If you can’t answer these questions with concrete evidence—not process documents, but actual system logs and access controls—you don’t have change control. You have change chaos with documentation.

The Fatal Pattern: Uncontrolled Change Management

Let me show you what compliance violation looks like in practice. This is the pattern I’ve seen in countless pre-certification assessments:

Fatal Example: The “We Trust Our Developers” Approach

# Developer on their laptop, any Tuesday morning
git clone https://github.com/company/production-api
cd production-api

# Make changes directly to main
git checkout main
# ... make changes ...
git add .
git commit -m "fix bug"
git push origin main

# Deployment happens automatically from main branch
# Or worse: developer runs deployment script manually
./deploy-to-prod.sh

What’s wrong here? Everything. Let’s enumerate the compliance failures:

  1. No authorization control: Any developer with write access can push to main
  2. No mandatory review: Changes reach production without peer review
  3. No testing gate: No required status checks, builds, or tests
  4. No separation of duties: Same person writes code and deploys to production
  5. Weak audit trail: Git log shows commits but not approval workflow
  6. No rollback procedure: No systematic way to revert changes safely
  7. Emergency bypass: “Hotfix” culture encourages skipping all controls “because urgent”

This pattern violates ISO 27001 fundamentally. You cannot demonstrate control. You cannot prove testing occurred. You cannot trace authorization. You cannot show segregation of duties.

When the auditor asks “show me how you prevent untested code from reaching production,” you have no technical answer. Only organizational promises that humans will follow the right process. That’s not a control. That’s hope.

The Hidden Risk: Cultural Normalization

The insidious aspect of this pattern is how normal it feels. Developers are trusted professionals. They know the codebase. They understand the risks. Surely they won’t deploy broken code to production?

Except they do. Not maliciously—accidentally. Under pressure. At 3 AM during an incident. When the customer is screaming. When the CEO is watching. Human processes fail under stress. That’s why ISO 27001 requires technical controls, not just process documentation.

The Compliant Pattern: GitHub Branch Protection

Now let me show you what compliance looks like when embedded in technical controls:

Correct Example: Branch Protection + Pull Request Workflow

Step 1: Branch Protection Configuration

# Branch protection rules for 'main' branch
# (Configured in GitHub repository Settings → Branches)

Protection Rules:
  - Require pull request before merging: 
  - Require approvals: 2
  - Dismiss stale reviews when new commits are pushed: 
  - Require review from code owners: 
  - Require status checks to pass before merging: 
  - Require signed commits: 
  - Include administrators: 
  - Allow force pushes: 
  - Allow deletions: 

This configuration ensures:

  • Authorization: Pull requests require explicit approval from designated reviewers
  • Review: Minimum two approvals enforced technically, not by policy
  • Testing: Status checks must pass—builds, tests, security scans—before merge is possible
  • Segregation: No direct pushes to main, even for administrators
  • Traceability: Every change linked to a pull request with full discussion history
  • Auditability: Complete record in GitHub audit log

Step 2: CODEOWNERS File for Domain Expert Review

# .github/CODEOWNERS

# Default owners for everything
* @team-leads

# Database migrations require DBA (Database Administrator) approval
/database/migrations/** @database-team

# Infrastructure as code requires ops review
/infrastructure/** @ops-team @security-team

# Payment processing requires specialized review
/src/payments/** @payments-team @compliance-officer

The result:

  • Mandatory expert review: Security-sensitive areas automatically require security team approval
  • Distributed responsibility: Domain experts own their areas explicitly
  • Compliance verification: Specific reviewers (like compliance officers) for regulated components
  • Audit evidence: Pull request history shows which experts reviewed each change

Step 3: Required Status Checks

# .github/workflows/pr-checks.yml
name: Pull Request Checks

on:
  pull_request:
    branches: [ main ]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build and test
        run: |
          dotnet build --configuration Release
          dotnet test --configuration Release
      
  security-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run security analysis
        uses: github/codeql-action/analyze@v3

Benefits:

  • Automated testing gate: Code must build, pass tests, and meet quality standards
  • Security verification: Automated security scanning catches vulnerabilities before merge
  • Quality enforcement: Code formatting and static analysis prevent quality degradation
  • Compliance evidence: Workflow run logs prove testing occurred

Step 4: Deployment Workflow with Environment Protection

# .github/workflows/deploy-production.yml
name: Deploy to Production

on:
  push:
    branches: [ main ]

jobs:
  deploy-production:
    runs-on: ubuntu-latest
    environment: production
    
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: az webapp deploy --resource-group prod-rg --name api --src-path ./release.zip
      - name: Verify deployment
        run: curl -f https://api.company.com/health

Environment Protection Configuration:

# Settings → Environments → production
Environment Protection Rules:
  - Required reviewers: @ops-lead, @security-lead
  - Wait timer: 5 minutes
  - Deployment branches: main only

This delivers:

  • Deployment authorization: Production deployments require explicit approval from designated leads
  • Segregation of duties: Developers cannot trigger production deployments directly
  • Cooling-off period: 5-minute wait prevents panic deployments
  • Automated verification: Smoke tests confirm deployment succeeded
  • Complete audit trail: GitHub deployment history records who approved, when, and what was deployed

How This Satisfies ISO 27001 Audit Requirements

Let’s map these technical controls directly to ISO 27001 requirements:

Control A.12.1.2 (Change Management)

Requirement: “Changes to the organization, business processes, information processing facilities and systems that affect information security shall be controlled.”

Technical Evidence:

  • Pull request workflow demonstrates formal change control procedure
  • Required approvals prove authorization before implementation
  • Status checks demonstrate testing and security validation
  • GitHub audit log provides complete change history
  • CODEOWNERS ensures security team reviews security-sensitive changes

Control A.14.2.2 (System Change Control Procedures)

Requirement: “Changes to systems within the development lifecycle shall be controlled by the use of formal change control procedures.”

Technical Evidence:

  • Branch protection prevents uncontrolled changes
  • Required status checks enforce testing in development lifecycle
  • Pull request reviews document technical review process
  • Deployment workflows enforce controlled release procedures
  • Environment protection gates ensure authorization before production deployment

Control A.14.2.9 (System Acceptance Testing)

Requirement: “Acceptance testing programs and related criteria shall be established for new information systems, upgrades and new versions.”

Technical Evidence:

  • Required status checks include automated test execution
  • Integration tests validate system behavior
  • Security scans verify security requirements
  • Deployment workflows include smoke tests for acceptance validation
  • Test execution logs prove testing occurred before production deployment

The Audit Evidence Package

When the auditor asks “show me your change control process,” you present:

  1. Branch Protection Configuration: Screenshot or exported settings showing technical controls
  2. Pull Request History: Demonstrating approval workflow, reviewer identity, timestamp
  3. Status Check Logs: Showing builds, tests, security scans passed before merge
  4. CODEOWNERS File: Proving security team mandatory review for security-sensitive code
  5. Deployment History: GitHub deployments page showing who approved, when deployed
  6. Audit Log Export: Complete GitHub audit log showing access, approvals, merges
  7. Rollback Procedure: Documented process using Git tags and revert workflows

This is concrete, technical, auditable evidence. Not process documents. Not promises. System-enforced controls that make compliance violations technically impossible.

Rollback Procedures: The Missing Control

One frequently overlooked aspect of ISO 27001 change control: demonstrable rollback capability. When a change causes a production incident, you need a systematic, tested procedure to revert to the last known good state.

Rollback Workflow

# .github/workflows/rollback-production.yml
name: Rollback Production

on:
  workflow_dispatch:
    inputs:
      target_tag:
        description: 'Git tag to rollback to (e.g., v2.1.4)'
        required: true

jobs:
  rollback:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ inputs.target_tag }}
      - name: Deploy rollback
        run: az webapp deploy --resource-group prod-rg --name api --src-path ./release.zip
      - name: Verify rollback
        run: curl -f https://api.company.com/health

Key outcomes:

  • Controlled rollback: Rollback requires same environment protection as deployment
  • Validation: Ensures rollback target is a valid, previously deployed version
  • Audit trail: Records who executed rollback, to which version, and when
  • Testing: Automated smoke tests verify rollback succeeded

Tagging Strategy for Rollback

# Automated tagging in deployment workflow
# Every successful production deployment creates a Git tag

- name: Tag successful deployment
  run: |
    VERSION=$(cat version.txt)  # e.g., 2.1.5
    git tag -a "v${VERSION}" -m "Production deployment $(date -u)"
    git push origin "v${VERSION}"

This creates a complete deployment history. Each tag represents a known-good production state. Rollback becomes straightforward: redeploy from a previous tag.

Common Pitfalls: Where Teams Fail Compliance

Even with these controls configured, I’ve seen teams accidentally violate their own compliance by:

Pitfall 1: Emergency Bypass Mechanisms

# DON'T: "Break glass" override that defeats all controls
# Some teams create a separate branch or emergency workflow
# that bypasses required reviews "for emergencies"

# This violates ISO 27001 immediately
# Emergency changes must ALSO follow change control procedures

ISO 27001 doesn’t have an “unless it’s urgent” exception. Emergency changes require expedited procedures with the same controls—faster approvals, not bypassed approvals.

Pitfall 2: Administrator Exemptions

# DON'T: Exclude administrators from branch protection
Protection Rules:
  - Include administrators:  # WRONG - creates compliance gap

If administrators can bypass controls, auditors will note the gap. Include administrators in protection rules. If emergencies require override, use GitHub’s temporary bypass mechanism with full audit logging.

Pitfall 3: Manual Deployment Scripts

# DON'T: Deployment scripts runnable from developer laptops
# Even if main branch is protected, if deployments happen manually
# you've lost segregation of duties

./deploy-prod.sh  # This should not exist

All production deployments must flow through GitHub Actions with environment protection. No deployment scripts on developer machines. No SSH access to production servers. No “just this once because urgent.”

Pitfall 4: Incomplete Audit Logging

GitHub’s built-in audit log is extensive, but it has retention limits (90-180 days depending on plan). For long-term compliance, you need:

# .github/workflows/export-audit-logs.yml
name: Export Audit Logs

on:
  schedule:
    - cron: '0 2 * * 0'  # Weekly

jobs:
  export:
    runs-on: ubuntu-latest
    steps:
      - name: Export and archive audit logs
        run: |
          gh api /orgs/{org}/audit-log --paginate > audit-log-$(date +%Y%m%d).json
          az storage blob upload --account-name complianceaudit --container-name logs --file audit-log-*.json

ISO 27001 expects audit logs retained for the full audit period (typically 3-7 years). GitHub’s retention isn’t sufficient. Export and archive.

Beyond Compliance: The Quality Benefits

Here’s the pragmatic reality: these controls don’t just satisfy auditors. They improve code quality, reduce production incidents, and make teams more productive.

Mandatory peer review catches bugs. I’ve seen data from teams that introduced required reviews: production incident rates dropped 40-60% within three months. Not because developers suddenly got better at coding, but because a second set of eyes spotted issues before merge.

Automated testing prevents regressions. Required status checks mean broken code never reaches main branch. Test failures block merge. You catch problems in pull requests, not production.

Security scanning reduces vulnerabilities. Automated CodeQL analysis and dependency scanning catch security issues before they ship. You fix them in development, not after exploitation.

Deployment gates prevent panic changes. The 5-minute cooling-off period and required approval for production deployments stops teams from making panicked changes during incidents. You think first, deploy second.

ISO 27001 compliance doesn’t fight against development velocity. It reinforces the practices that high-performing teams already use. The controls aren’t bureaucracy—they’re engineering discipline codified.

Practical Implementation Path

If you’re approaching ISO 27001 certification, here’s the pragmatic implementation sequence:

Week 1: Enable Branch Protection

  • Configure main branch protection with pull request requirement
  • Add minimum two required approvals
  • Prevent direct pushes to main
  • Include administrators in restrictions

Week 2: Implement Status Checks

  • Create GitHub Actions workflow for build + test
  • Add security scanning (CodeQL)
  • Add code quality checks
  • Configure these as required status checks

Week 3: Create CODEOWNERS

  • Identify security-sensitive code paths
  • Assign domain experts as code owners
  • Configure required review from code owners

Week 4: Deploy Environment Protection

  • Create production environment in GitHub
  • Configure required approvers (ops + security leads)
  • Migrate deployment workflows to use environment protection
  • Remove manual deployment scripts

Week 5: Implement Rollback Procedures

  • Create rollback workflow with environment protection
  • Implement automated tagging for deployments
  • Test rollback procedure with non-production environment
  • Document rollback process for operations team

Week 6: Audit Log Archival

  • Set up automated audit log export
  • Configure long-term archival storage
  • Verify export and retrieval procedures
  • Document retention policy

This gives you six weeks to implement compliant change control. Not six months. Not a year-long initiative. Six weeks of focused engineering work.

Conclusion: Compliance Through Technical Control

ISO 27001 change control isn’t about documentation. It’s not about process manuals. It’s not about trusting humans to follow procedures under pressure.

It’s about technical controls that make compliance violations impossible. Branch protection that prevents unreviewed code from reaching production. Required status checks that block merges when tests fail. Environment protection that demands explicit authorization before deployment. Audit logs that record every action, every approval, every change.

GitHub provides these controls natively. You don’t need expensive compliance platforms. You don’t need complex workflows. You don’t need bureaucratic overhead. You need to configure the tools you already have to enforce the controls ISO 27001 requires.

The teams that struggle with compliance are the ones trying to prove they follow processes. The teams that succeed are the ones who enforce processes through technical controls. When the auditor asks “show me your change control,” you don’t present a process document. You show them your branch protection configuration, your pull request history, your deployment logs, your audit trail.

That’s evidence. That’s compliance. That’s how modern software teams satisfy ISO 27001 without sacrificing development velocity or burying engineers in compliance theater.

Configure these controls. Enforce them technically. Document the evidence. Pass the audit. Then get back to building software—knowing that your change control process is working in the background, preventing the catastrophic mistakes that destroy certifications and damage customer trust.

Comments

VG Wort