Compliance Quick Start Guide
This page describes technical features that can support your compliance work. It is not legal advice, and it does not establish that any system is compliant with any law, regulation or standard. You remain responsible for your own compliance assessment, independent testing and validation, and review by qualified legal and compliance professionals. See the Compliance Disclaimer.
Framework: Excalibur Audience: First-time users implementing compliance features Last Updated: 2026-09-12
Before You Start
- .NET 10.0
- Install the required packages:
dotnet add package Excalibur.Security
- Familiarity with security overview and audit logging
Overview
This guide walks you through implementing baseline compliance capabilities using the Excalibur framework in under an hour. You'll:
- Choose your compliance framework(s)
- Install required packages
- Configure core security capabilities
- Verify installation with conformance tests
- Understand next steps for full certification
After this guide: You'll have working encryption, audit logging, and access control - the foundation for FedRAMP, GDPR, SOC 2, or HIPAA compliance. For full certification, follow the detailed checklists.
Prerequisites
Required:
- .NET 10.0 SDK
- Visual Studio 2022, VS Code, or Rider
- Basic C# knowledge
- NuGet package management
Optional but Recommended:
- Azure Key Vault or AWS KMS account (for production encryption)
- SQL Server or Postgres (for audit log persistence)
- GitHub account (for evidence collection from CI/CD)
Step 1: Choose Your Framework
Decision Tree
Question 1: What data do you process?
Are you selling to US federal government?
├─ YES → FedRAMP (Required for government contracts)
└─ NO → Continue
Do you process EU resident data?
├─ YES → GDPR (Legally required for EU data)
└─ NO → Continue
Do you handle healthcare data (PHI)?
├─ YES → HIPAA (Legally required for healthcare)
└─ NO → Continue
Are you a B2B SaaS/cloud provider?
├─ YES → SOC 2 (Customer requirement)
└─ NO → Consider SOC 2 for trust/credibility
Framework Comparison
| Framework | Primary Audience | Mandatory? | Key Benefit | Certification Time |
|---|---|---|---|---|
| FedRAMP | Government contractors | Yes (for fed contracts) | Access to federal market | 6-12 months |
| GDPR | EU data processors | Yes (EU residents) | Legal compliance, avoid fines | 3-6 months |
| SOC 2 | B2B SaaS providers | No (but expected) | Customer trust, RFP requirement | 3-18 months |
| HIPAA | Healthcare sector | Yes (PHI processing) | Legal compliance, patient trust | 6-12 months |
Can you pursue multiple frameworks? Yes! The framework capabilities overlap significantly:
- FedRAMP + SOC 2: Common for government SaaS
- GDPR + SOC 2: Common for EU SaaS
- HIPAA + SOC 2: Common for healthcare SaaS
Recommendation: Start with GDPR or SOC 2 as a baseline, then add others as needed.
Step 2: Install Packages
Core Packages
All frameworks require the core security packages:
# Core domain capabilities (required for all)
dotnet add package Excalibur.Domain
# Compliance features (GDPR erasure, SOC 2 validation)
dotnet add package Excalibur.Compliance
# Event sourcing (optional, for audit trail + domain events)
dotnet add package Excalibur.EventSourcing
Framework-Specific Packages
For Production (SQL Server persistence):
# Audit log persistence
dotnet add package Excalibur.AuditLogging.SqlServer
# Erasure requests, legal holds persistence
dotnet add package Excalibur.Compliance.SqlServer
# Event sourcing + outbox (optional)
dotnet add package Excalibur.EventSourcing.SqlServer
For Audit Logging:
# Core audit logging (includes in-memory store)
dotnet add package Excalibur.AuditLogging
For Testing:
# Conformance test kits (ErasureStore, LegalHoldStore, DataInventoryStore, AuditStore)
dotnet add package Excalibur.Testing.Conformance
# Test doubles and in-memory infrastructure (optional, separate package)
dotnet add package Excalibur.Testing
The conformance kits ship in Excalibur.Testing.Conformance. Excalibur.Testing carries test
doubles and in-memory stores and does not contain them — install the conformance package or the
filters in Step 4 will match nothing.
Step 3: Configure Core Capabilities
3.1 Access Control (All Frameworks)
Required for: FedRAMP (AC-3, AC-6), GDPR (Art 32), SOC 2 (CC5), HIPAA (§164.312(a))
Configuration:
// Program.cs or Startup.cs
var builder = WebApplication.CreateBuilder(args);
// Add ASP.NET Core authorization with policy-based access control
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("ViewPatients", policy =>
policy.RequireClaim("permission", "patients.read"));
options.AddPolicy("EditPatients", policy =>
policy.RequireClaim("permission", "patients.write"));
});
The [RequirePermission] attribute is provided by the Excalibur.A3 package (namespace Excalibur.A3.Authorization). For basic access control, use ASP.NET Core's built-in [Authorize] policies as shown above.
3.2 Encryption (FedRAMP, GDPR, SOC 2, HIPAA)
Required for: FedRAMP (SC-28), GDPR (Art 25, 32), SOC 2 (C2), HIPAA (§164.312(a)(2)(iv))
Development Configuration (In-Memory):
// Development only — keys are NOT persisted!
builder.Services.AddDevEncryption();
Production Configuration (Fluent Builder):
builder.Services.AddEncryption(encryption => encryption
.UseKeyManagement<AesGcmEncryptionProvider>("aes-gcm-primary")
.ConfigureOptions(options => options.DefaultPurpose = "field-encryption"));
The AddEncryption() API uses a fluent builder pattern. Call .UseKeyManagement<TProvider>(name) to register your provider, then .ConfigureOptions() for settings. AesGcmEncryptionProvider and RotatingEncryptionProvider ship with the framework; to back field encryption with an external KMS, implement IEncryptionProvider against it — no cloud-KMS IEncryptionProvider is shipped.
Message-signing key material is a separate extension point (IKeyProvider), and cloud-backed implementations of that one are shipped:
dotnet add package Excalibur.Security.Azure # AddAzureKeyVaultKeyProvider()
dotnet add package Excalibur.Security.Aws # AddAwsSecretsManagerKeyProvider()
Do not reach for these expecting them to encrypt [PersonalData] fields; they supply signing keys, and an unknown key fails closed rather than being minted on retrieval.
Usage (Data Classification Attributes):
using Excalibur.Compliance;
public class Patient
{
public Guid Id { get; set; }
[PersonalData] // Marks field as personal data
public string FirstName { get; set; }
[PersonalData]
public string LastName { get; set; }
[PersonalData]
[Sensitive] // In every released version: classification + masked in logs, no encryption.
// On the main branch it also selects the property for encryption at rest.
public string SSN { get; set; }
public DateTime DateOfBirth { get; set; } // NOT marked
}
3.3 Audit Logging (All Frameworks)
Required for: FedRAMP (AU-2, AU-3, AU-9), GDPR (Art 32), SOC 2 (CC4), HIPAA (§164.312(b))
Development Configuration (In-Memory):
// Package: Excalibur.AuditLogging
// Default in-memory store for development/testing
builder.Services.AddAuditLogging();
Production Configuration (SQL Server):
// Package: Excalibur.AuditLogging.SqlServer
builder.Services.AddSqlServerAuditStore(options =>
{
options.ConnectionString = builder.Configuration.GetConnectionString("Compliance")!;
options.SchemaName = "audit"; // matches the schema 001_CreateAuditSchema.sql creates
options.EnableHashChain = true;
});
Usage:
using Excalibur.Compliance;
public class PatientService
{
private readonly IAuditStore _auditStore;
public async Task<Patient> GetPatientAsync(Guid patientId, CancellationToken ct)
{
var patient = await _repository.GetAsync(patientId, ct);
// Audit access
await _auditStore.StoreAsync(new AuditEvent
{
EventId = Guid.NewGuid().ToString(),
EventType = AuditEventType.DataAccess,
Action = "Patient.Read",
ActorId = _currentUser.Id,
ResourceId = patientId.ToString(),
ResourceType = "Patient",
Outcome = AuditOutcome.Success,
Timestamp = DateTimeOffset.UtcNow
}, ct);
return patient;
}
}
3.4 GDPR Erasure (GDPR + Optional for Others)
Required for: GDPR (Art 17) Recommended for: SOC 2 (C3), HIPAA (Secure disposal)
Configuration:
using Excalibur.Compliance;
builder.Services.AddGdprErasure(options =>
{
options.DefaultGracePeriod = TimeSpan.FromHours(72);
options.RequireVerification = true;
});
// Development (in-memory stores)
builder.Services.AddInMemoryErasureStore();
builder.Services.AddInMemoryLegalHoldStore();
builder.Services.AddInMemoryDataInventoryStore();
// Supporting services
builder.Services.AddLegalHoldService();
builder.Services.AddDataInventoryService();
builder.Services.AddErasureVerificationService();
builder.Services.AddErasureScheduler();
Usage:
using Excalibur.Compliance;
public class UserController : ControllerBase
{
private readonly IErasureService _erasureService;
[HttpPost("erasure-requests")]
public async Task<IActionResult> RequestErasure(
[FromBody] ErasureRequestDto dto,
CancellationToken ct)
{
var result = await _erasureService.RequestErasureAsync(new ErasureRequest
{
DataSubjectId = dto.UserId,
IdType = DataSubjectIdType.UserId,
LegalBasis = ErasureLegalBasis.DataSubjectRequest,
RequestedBy = User.Identity?.Name ?? "anonymous"
}, ct);
return Ok(new { result.RequestId, result.Status, result.ScheduledExecutionTime });
}
}
3.5 SOC 2 Validation (SOC 2 Only)
Configuration:
using Excalibur.Compliance;
builder.Services.AddSoc2ComplianceWithBuiltInValidators(options =>
{
options.EnabledCategories =
[
TrustServicesCategory.Security,
TrustServicesCategory.Availability,
TrustServicesCategory.Confidentiality
];
});
// Development
builder.Services.AddInMemorySoc2ReportStore();
// Optional: Continuous monitoring
builder.Services.AddSoc2ComplianceWithMonitoring(options =>
{
options.Monitoring.MonitoringInterval = TimeSpan.FromHours(1);
options.Monitoring.AlertThreshold = GapSeverity.Medium;
});
Step 4: Verify Installation
4.1 Run Conformance Tests
The framework ships conformance kits you use to verify your implementation. The kits carry no test
attributes — every arm is virtual, so nothing runs until you declare an attributed wrapper in your own
derived class. You choose which arms to wrap; the executed count is yours, not ours.
The --RunConfiguration.TreatNoTestsAsError=true flag below matters for that reason: without it, a filter
that matches nothing exits successfully and reads as a pass.
# Run all GDPR conformance tests. Expected: all PASS, and a non-zero Total on each run
# VSTest (default)
dotnet test --filter "FullyQualifiedName~ErasureStoreConformance" --blame-hang-timeout 5m -- RunConfiguration.TreatNoTestsAsError=true
dotnet test --filter "FullyQualifiedName~LegalHoldStoreConformance" --blame-hang-timeout 5m -- RunConfiguration.TreatNoTestsAsError=true
dotnet test --filter "FullyQualifiedName~DataInventoryStoreConformance" --blame-hang-timeout 5m -- RunConfiguration.TreatNoTestsAsError=true
dotnet test --filter "FullyQualifiedName~AuditStoreConformance" --blame-hang-timeout 5m -- RunConfiguration.TreatNoTestsAsError=true
# Microsoft.Testing.Platform
dotnet test --filter "FullyQualifiedName~ErasureStoreConformance" --blame-hang-timeout 10m -- --timeout 5m --minimum-expected-tests 1
dotnet test --filter "FullyQualifiedName~LegalHoldStoreConformance" --blame-hang-timeout 10m -- --timeout 5m --minimum-expected-tests 1
dotnet test --filter "FullyQualifiedName~DataInventoryStoreConformance" --blame-hang-timeout 10m -- --timeout 5m --minimum-expected-tests 1
dotnet test --filter "FullyQualifiedName~AuditStoreConformance" --blame-hang-timeout 10m -- --timeout 5m --minimum-expected-tests 1
Which of the two forms you need depends on the test runner your project uses, and picking the wrong one fails in a way that does not name the cause:
- VSTest (the default).
RunConfiguration.TreatNoTestsAsError=trueis required — without it a filter that matches nothing exits0and reads as a pass. - Microsoft.Testing.Platform (
<UseMicrosoftTestingPlatform>true</UseMicrosoftTestingPlatform>). Do not pass the setting above: the native test host does not recognise it, prints its help text and exits non-zero on every run, whether or not the filter matched. Pass--minimum-expected-tests 1instead — a run that executes fewer tests than the minimum, including zero, exits with code9. This matters more here than the filter case, because conformance arms skip themselves. An arm whose capability your provider does not implement reports skipped, not failed. MTP's--zero-tests-policydefaults toallow-skipped, so a run in which every arm skipped succeeds — the checklist item would read as passed on a run that verified nothing. Either pass a minimum as above, or pass--zero-tests-policy strict(available from MTP 2.3.0), which fails an all-skipped run with exit code8. An explicit minimum supersedes the policy.
Both forms below also carry a hang bound, so a wedged test host ends the run with evidence instead of occupying your pipeline until it is killed.
The VSTest form carries RunConfiguration.TreatNoTestsAsError=true deliberately. Without it, dotnet test --filter exits 0 when the filter matches nothing — so if you have not referenced the conformance
package, or a type has been renamed, the command prints No test matches the given testcase filter and
succeeds. The checklist item would read as passed on a run that verified nothing, which is the state
this instruction exists to detect.
With the setting, a filter that matches no tests fails the command. Confirm the summary reports a
non-zero Total — an exit code alone is not evidence that a check ran.
Then read the process exit code, and take it as the verdict. The two answer different questions: a
non-zero Total tells you a check ran, and only the exit code tells you whether it passed. Do not
record the result from the summary line. Through the dotnet test bridge an assembly-level cleanup
failure is reported outside the failure count, so the console can print Passed! with Failed: 0 on a
run that exited non-zero. Running the same assembly as a test executable prints the error and the exit
code agrees with it; the bridge's summary line does not. Capture $LASTEXITCODE (PowerShell) or $?
(POSIX shell) as the evidence, not the console text.
Test Breakdown:
- AuditStoreConformanceTestKit (audit logging)
- ErasureStoreConformanceTestKit (GDPR erasure)
- LegalHoldStoreConformanceTestKit (GDPR exceptions)
- DataInventoryStoreConformanceTestKit (RoPA)
Record the count your own run executed. No arm total is published here: any number we print is ours at some past moment, and only your run evidences your control.
4.2 Manual Verification
Test Encryption:
// Create a patient with encrypted fields
var patient = new Patient
{
Id = Guid.NewGuid(),
FirstName = "John",
LastName = "Doe",
SSN = "123-45-6789"
};
await _repository.SaveAsync(patient);
// Inspect database - should see encrypted values
// SELECT FirstName FROM Patients WHERE Id = '...'
// Result: "AQIDBAUGBwgJCgsMDQ4PEA==" (Base64 ciphertext)
Test Audit Logging:
// Access a patient
var patient = await _patientService.GetPatientAsync(patientId, ct);
// Query audit logs via IAuditStore
var events = await _auditStore.QueryAsync(new AuditQuery
{
Action = "Patient.Read",
StartDate = DateTimeOffset.UtcNow.AddMinutes(-5),
EndDate = DateTimeOffset.UtcNow
}, ct);
// Verify: Event logged with correct ActorId, Timestamp, ResourceId
Test Authorization:
// Try to access patient without permission
// Expected: UnauthorizedAccessException
// Grant permission, retry
// Expected: Success
Step 5: Next Steps
For Full Certification
Now that you have baseline compliance capabilities, follow the detailed checklists:
FedRAMP (6-12 months):
- Follow checklists/fedramp.md
- Weeks 1-9: Implement all 14 NIST 800-53 controls
- Week 10-12: Internal audit, penetration testing
- Engage FedRAMP-approved 3PAO
- Submit authorization package to PMO
GDPR (3-6 months):
- Follow checklists/gdpr.md
- Weeks 1-7: Implement Articles 17, 17(3), 25, 30, 32 and prepare breach notification
- Weeks 8-10: Conformance testing, policy development
- Conduct Data Protection Impact Assessment (DPIA)
- Schedule external audit (optional but recommended)
SOC 2 (3-18 months):
- Follow checklists/soc2.md
- Weeks 1-6: Implement Security + optional categories
- Weeks 7-8: Run automated validators, collect evidence
- Schedule SOC 2 Type I audit (CPA firm)
- Operate for 6-12 months, then SOC 2 Type II
HIPAA (6-12 months):
- Follow checklists/hipaa.md
- Engage HIPAA compliance specialist (REQUIRED)
- Weeks 1-7: Implement Technical Safeguards (§164.312)
- Weeks 8-12: Develop policies, train workforce
- Conduct Risk Assessment, schedule external audit
Evidence Collection
Automate Evidence Collection:
The framework's own evidence collectors live in eng/compliance/ in the
framework repository. They are not shipped in any NuGet package. To use them on
your own pipeline, copy that directory into your repository — each script reads
control-evidence-map.tsv from beside itself — and run it where the GitHub CLI (gh) is
authenticated against your repository:
# Windows
.\eng\compliance\collect-evidence.ps1 -Frameworks "FedRAMP,SOC2"
# Linux/macOS
./eng/compliance/collect-evidence.sh -f GDPR,HIPAA
They collect from GitHub Actions runs of a workflow named ci.yml and expect artifact names matching
the framework's own pipeline, so adapt the workflow and artifact names to yours. Every figure in the
resulting MANIFEST.json is derived from the files actually collected — a run that downloads nothing
reports zero controls documented rather than a default.
Monthly Evidence Collection:
Set up automated monthly evidence collection (see Evidence Automation for GitHub Actions workflow).
Training and Policies
All Frameworks Require:
- Security awareness training (annual)
- Privacy policy and notices
- Incident response procedures
- Business Associate Agreements (HIPAA, GDPR processors)
- Risk assessments (annual or when changes occur)
Framework-Specific:
- FedRAMP: System Security Plan (SSP), Security Assessment Report (SAR)
- GDPR: Records of Processing Activities (RoPA), Data Protection Impact Assessment (DPIA)
- SOC 2: System description, management assertion, control design documentation
- HIPAA: HIPAA Security Officer designation, Business Associate Agreements (BAAs)
Common Pitfalls
1. Using In-Memory Stores in Production
Problem: In-memory stores (audit, erasure, legal hold) are lost on restart.
Solution: Always use SQL Server stores for production:
// ❌ WRONG (Production) - uses in-memory storage
builder.Services.AddAuditLogging();
// ✅ CORRECT (Production)
builder.Services.AddSqlServerAuditStore(options =>
{
options.ConnectionString = configuration.GetConnectionString("Compliance")!;
options.EnableHashChain = true;
});
2. Forgetting to Annotate Sensitive Fields
Problem: Personal data not encrypted because [PersonalData] attribute is missing.
Solution: Audit all domain models and annotate sensitive fields:
// ❌ WRONG (No encryption)
public class Patient
{
public string SSN { get; set; } // Stored in plaintext!
}
// ✅ CORRECT (Encrypted at rest)
public class Patient
{
[PersonalData]
public string SSN { get; set; }
}
3. Not Running Conformance Tests
Problem: Implementation bugs discovered during external audit.
Solution: Wrap and run the conformance arms relevant to your controls before engaging an auditor:
# Run the conformance arms relevant to your controls
# VSTest (default)
dotnet test --filter "FullyQualifiedName~Conformance" --blame-hang-timeout 5m -- RunConfiguration.TreatNoTestsAsError=true
# Microsoft.Testing.Platform
dotnet test --filter "FullyQualifiedName~Conformance" --blame-hang-timeout 10m -- --timeout 5m --minimum-expected-tests 1
4. Skipping Organizational Controls
Problem: Framework provides technical controls, but organizational policies are missing.
Solution: Remember the framework provides technical capabilities, you must provide:
- Policies and procedures
- Workforce training
- Risk assessments
- Business Associate Agreements
- Incident response plans
5. Not Engaging Compliance Specialists
Problem: Attempting full compliance without professional guidance.
Solution: For FedRAMP, GDPR, SOC 2, and HIPAA, always engage a qualified compliance specialist or legal counsel. The framework provides technical tools, but compliance is a holistic business process.
Troubleshooting
Encryption Not Working
Symptom: Data is not encrypted in database.
Check:
- Is
[PersonalData]attribute applied to field? - Is
IEncryptionProviderregistered in DI? - Is encryption middleware configured?
- Check logs for encryption errors
Audit Logs Not Persisting
Symptom: Audit events logged but not in database.
Check:
- Is
IAuditStoreimplementation registered? - Is connection string correct?
- Have the audit tables been provisioned? The SQL Server audit store never creates its own table --
run the
001_CreateAuditSchema.sqlscript shipped in the package before the first write. - Check SQL Server permissions (INSERT required)
Conformance Tests Failing
Symptom: Some conformance tests fail.
Check:
- Are you using correct store implementations (not in-memory for tests)?
- Are all required services registered (e.g.,
ILegalHoldService)? - Check test output for specific error messages
- Review conformance test documentation
Resources
Documentation
This Repository:
- index.md - Compliance documentation index
- checklists/ - Detailed certification checklists
- ../security/ - Security implementation guides
- ../advanced/ - Advanced topics
External Standards:
Support
Questions:
- Product Manager: Compliance scope, legal basis
- Software Architect: Technical implementation
- Project Manager: Evidence packages, audit coordination
Issues:
- GitHub Issues:
compliancelabel
Summary Checklist
Before proceeding to full certification, verify:
- Installed required NuGet packages
- Configured access control (ASP.NET Core authorization policies)
- Configured encryption (
AddEncryption()orAddDevEncryption()+[PersonalData]) - Configured audit logging (
IAuditStoreviaAddAuditLogging()orAddSqlServerAuditStore()) - Configured GDPR erasure (
IErasureService) - if applicable - Configured SOC 2 validation - if applicable
- Wrapped the conformance arms covering your controls, and recorded the executed/passed counts from your own run
- Verified encryption in database (ciphertext visible)
- Verified audit logs persisting
- Verified authorization enforcement
- Reviewed detailed checklist for chosen framework(s)
- Engaged compliance specialist or legal counsel
- Documented system architecture and data flows
- Developed initial policies and procedures
You're Ready! Proceed to the detailed checklists for full certification.
Last Updated: 2026-09-12 Framework Version: Excalibur 10.0.0 prerelease
See Also
- Compliance Overview — Main compliance documentation index with framework capabilities and certification roadmap
- Audit Logging — Detailed guide for configuring audit logging with SQL Server persistence
- GDPR Erasure — Implement right-to-erasure with legal holds and verification
- Security Overview — Security implementation guides for encryption, access control, and key management