Post

Dunderly HR System: Governance and Compliance

Dunderly HR governance: a small steering group, ADRs for decisions, quarterly access reviews of who sees salaries, Azure Policy guardrails and evidence that collects itself.

Dunderly HR System: Governance and Compliance

Governance for a 250-person company’s HR system should fit on a page, and most of it should run without anyone remembering to do it. The two questions an auditor, a regulator or an unhappy employee will ask are “who can see salaries?” and “who approved this change?”. If the system answers both instantly, with evidence, most of the governance work is already done.

Project governance

ForumWhoWhenDecides
Steering groupSponsor, HR manager, IT lead, architectEvery 2 weeks during build; quarterly afterScope, budget, go-live, risk acceptance
Sprint reviewTeam + HR product owner (+ HR users)Every sprintAccept stories; reprioritize backlog
Architecture reviewArchitect + dev lead (+ IT for integration changes)Monthly during build; quarterly afterADRs
Change advisory (light)Product owner + architectAs neededPayroll-impacting releases

The steering group gets a one-page status every two weeks: progress against milestones, top risks, decisions needed, budget. Red items come with a proposed decision, not just a problem.

Decision-making and approval authorities

DecisionWho decidesWho’s consulted
Scope and MVP changesSponsorHR manager, architect
Business rules (salary, leave, payroll)HR managerPayroll operator, legal
Architecture and technologyArchitect (via ADR)Dev lead, IT
Payroll file formatPayment system owner + payroll operatorArchitect
Production releaseTech lead / architectProduct owner; payroll operator if risk:payroll
Access to salary data (role assignments)HR managerIT
Risk acceptanceSponsorArchitect, DPO
Go-liveSponsorSteering group

Architecture decisions are written as ADRs in docs/adr/ (see the ADR list). An ADR is never edited after acceptance; a new one supersedes it. That’s how the 2023 decisions and the modernized ones can both stay visible, with the reasoning for each change.

Audit requirements

What has to be provable, and how:

RequirementEvidence
Every salary change was requested and approved by different peopleSalaryRequest with RequestedBy ≠ DecidedBy, plus audit events
Every payroll run was prepared and approved by different peoplePayrollRun prepared/approved fields; audit events
What was paid matches what was approvedRun snapshot + file SHA-256 + receipt
Who accessed or changed an employee’s dataAudit events; SQL auditing for direct access
Who had access to salary data at any timeEntra ID group membership history + access review records

TODO: Does Dunderly have an external auditor who’ll examine payroll controls (for example as part of the annual financial audit)? If so, share this table with them before go-live; they may want more.

Access reviews

Quarterly Entra ID access reviews on the groups that grant sensitive roles (HR.Manager, HR.Admin, Payroll.Operator, Auditor), reviewed by the HR manager, with “deny if no response” so forgotten access expires. Manager access needs no review: it’s derived from the reporting line in the HR data, so it changes when the org chart does.

Azure access (who can touch production resources) is reviewed the same way, and admin roles are PIM-eligible rather than permanent. See Access Reviews and PIM.

Assumption: Dunderly has Entra ID P2 (or Entra ID Governance) for access reviews and PIM. Without it, the review is a manual quarterly export of group members, signed off by the HR manager.

License management

Two kinds of licenses:

  • Software dependencies. The dependency review action blocks copyleft licenses that would conflict with a closed-source internal app (GPL family) unless approved. Today’s stack is MIT and Apache 2.0.
  • Microsoft licensing. Entra ID P1 for Conditional Access (P2 for access reviews and PIM), and the Azure support plan. These are often already in a Microsoft 365 E3/E5 agreement; check before buying.

Fluent UI Blazor, EF Core, ASP.NET Core and the Azure SDKs are MIT licensed. Playwright, xUnit and k6 are build-time only.

Compliance reporting

A quarterly one-pager for the steering group and the DPO, mostly generated by queries:

  • Salary changes in the quarter: count, all with four-eyes approval (yes/no).
  • Payroll runs: all delivered on time, all receipts present.
  • Access review completion and removals.
  • Security: open findings by severity vs remediation SLA; Defender secure score.
  • Privacy: subject access requests handled and time taken; retention purges run.
  • Incidents and their reviews.

Data governance

HR is the data owner; the HR manager is the named owner for salary and payroll data. Practical rules:

  • The HR system is the source of truth for employee, reporting line, salary and leave. Other systems read from it, never the other way round.
  • Classification per data set (see Data ownership) decides where data may appear.
  • Retention is enforced by the monthly job, and its runs are logged as evidence.
  • Any new use of HR data (a report for finance, a feed to another system) needs the HR manager’s and the DPO’s approval, recorded as a change note.

Vendor and third-party management

The third parties are few:

VendorRoleAssurance
Microsoft (Azure, Entra ID, M365)Hosting, identityMicrosoft’s DPA and compliance reports (ISO 27001, SOC 2) via the Service Trust Portal
GitHub (Microsoft)Source code, CISame; no HR data in GitHub, ever
Legacy payment systemInternal, but a separate ownerAn internal interface agreement: file format, schedule, receipt, contacts

The interface agreement with the payment system’s owner is the one that matters most, because they’re not under the app team’s control. It’s written down, versioned with the file format doc, and reviewed whenever either side changes.

Policy enforcement

Guardrails as code, so they hold without anyone checking:

  • Azure Policy on the HR subscription or resource groups: allowed regions (West Europe, North Europe), deny public network access on SQL and Key Vault, require TLS 1.2, require diagnostic settings, require tags, deny storage accounts with shared key access.
  • Branch protection and CODEOWNERS for code and payroll review rules.
  • GitHub environment rules for production deployments.
  • Conditional Access for MFA and device compliance.
  • Database permissions: append-only audit table; DDL only for the pipeline identity.

Policies start in audit mode in dev, then deny everywhere once nothing violates them.

Evidence collection

Evidence should collect itself:

EvidenceSourceKept
Approvals of salary and payrollSQL audit eventsWith the HR record
Releases and who approved themGitHub deployment historyGitHub retention + release notes
Code reviewPR historyRepo
Access reviewsEntra ID access review historyExported quarterly
Policy complianceAzure Policy compliance stateExported quarterly
Restore and DR testsRunbook “last tested” entries + test notesRepo
Pen test and remediationReport + issuesRestricted folder

Quarterly, a scheduled workflow exports the non-repo evidence into a restricted storage container with an immutability policy, so the evidence for a quarter can’t be edited afterwards.

Checklist

  • Set up the steering group and its two-weekly one-pager.
  • Agree the decision table with the sponsor.
  • Confirm Entra ID P1/P2 licensing for Conditional Access, access reviews and PIM.
  • Create the quarterly access reviews for sensitive role groups.
  • Assign the Azure Policy initiative, audit first then deny.
  • Write the interface agreement with the payment system’s owner.
  • Ask whether an external auditor will examine payroll controls.

This post is licensed under CC BY 4.0 by the author.