SecurityRules.java
package com.cloudforgeci.api.core.rules;
import com.cloudforgeci.api.core.SystemContext;
import com.cloudforgeci.api.core.security.DevSecurityConfiguration;
import com.cloudforgeci.api.core.security.ProductionSecurityConfiguration;
import com.cloudforgeci.api.core.security.StagingSecurityConfiguration;
import com.cloudforgeci.api.core.security.DevSecurityProfileConfiguration;
import com.cloudforgeci.api.core.security.StagingSecurityProfileConfiguration;
import com.cloudforgeci.api.core.security.ProductionSecurityProfileConfiguration;
import com.cloudforgeci.api.interfaces.SecurityConfiguration;
import com.cloudforgeci.api.interfaces.SecurityProfileConfiguration;
import com.cloudforgeci.api.interfaces.Rule;
import com.cloudforge.core.interfaces.FrameworkRules;
import io.github.cdklabs.cdknag.AwsSolutionsChecks;
import io.github.cdklabs.cdknag.HIPAASecurityChecks;
import io.github.cdklabs.cdknag.NagReportFormat;
import io.github.cdklabs.cdknag.PCIDSS321Checks;
import io.github.cdklabs.cdknag.NagPack;
import software.amazon.awscdk.Aspects;
import com.cloudforge.core.enums.ComplianceMode;
import com.cloudforge.core.enums.SecurityProfile;
import java.util.*;
import java.util.logging.Logger;
/**
* Security rules installation and compliance framework orchestration.
*
* <p>This class coordinates security profile configuration and compliance framework
* validation. Starting in v3.0.0, it uses auto-discovery to load compliance frameworks,
* enabling plugin-based extensibility.</p>
*
* <h2>Version History:</h2>
* <ul>
* <li><strong>v3.0.0:</strong> Hardcoded framework loading</li>
* <li><strong>v3.0.0:</strong> Auto-discovery via {@link FrameworkLoader} with backward compatibility</li>
* <li><strong>v4.0.0 (future):</strong> Pure plugin-based architecture</li>
* </ul>
*
* @since 3.0.0
*/
public final class SecurityRules {
private static final Logger LOG = Logger.getLogger(SecurityRules.class.getName());
public static void install(SystemContext ctx) {
// Create and set the SecurityProfileConfiguration in SystemContext
// Pass deployment context so security profiles can override defaults
final SecurityProfileConfiguration profileConfig = switch (ctx.security) {
case DEV -> new DevSecurityProfileConfiguration(ctx.cfc);
case STAGING -> new StagingSecurityProfileConfiguration(ctx.cfc);
case PRODUCTION -> new ProductionSecurityProfileConfiguration(ctx.cfc);
};
ctx.securityProfileConfig.set(profileConfig);
final SecurityConfiguration p = switch (ctx.security) {
case DEV -> new DevSecurityConfiguration();
case STAGING -> new StagingSecurityConfiguration();
case PRODUCTION -> new ProductionSecurityConfiguration();
};
ctx.getNode().addValidation(() -> {
List<String> errs = new ArrayList<>();
for (Rule r : p.rules(ctx)) errs.addAll(r.check(ctx));
return errs;
});
ctx.once("ProfileWiring:Security:" + p.kind(), () -> {
p.wire(ctx);
});
// Get enabled compliance frameworks (comma-separated list)
String frameworksConfig = ctx.cfc.complianceFrameworks();
// Parse enabled frameworks into a set for fast lookup
Set<String> enabledFrameworks = (frameworksConfig == null || frameworksConfig.trim().isEmpty())
? Collections.emptySet()
: Arrays.stream(frameworksConfig.split(","))
.map(String::trim)
.map(String::toUpperCase)
.collect(java.util.stream.Collectors.toSet());
// CDK-nag validation only runs for PRODUCTION with enabled frameworks
if (ctx.security == SecurityProfile.PRODUCTION && !enabledFrameworks.isEmpty()) {
applyCdkNagValidation(ctx, enabledFrameworks);
}
// CloudForge FrameworkRules validation requires auditManagerEnabled
if (!Boolean.TRUE.equals(ctx.cfc.auditManagerEnabled())) {
LOG.info("Skipping CloudForge FrameworkRules validation (auditManagerEnabled = false)");
return;
}
// Log what we're doing
if (enabledFrameworks.isEmpty()) {
LOG.info("No compliance frameworks specified - installing only alwaysLoad validators (e.g., ConfigurationValidationRules)");
} else {
LOG.info("Installing CloudForge FrameworkRules validation for: " + frameworksConfig);
}
// Discover all available compliance frameworks (v3.0.0 plugin architecture)
List<FrameworkRules<SystemContext>> allFrameworks = FrameworkLoader.discover();
LOG.info("Discovered " + allFrameworks.size() + " compliance frameworks");
// Install frameworks in priority order
int installedCount = 0;
for (FrameworkRules<SystemContext> framework : allFrameworks) {
boolean shouldInstall = framework.alwaysLoad() ||
enabledFrameworks.contains(framework.frameworkId().toUpperCase());
if (shouldInstall) {
try {
framework.install(ctx);
installedCount++;
LOG.info(" ✓ " + framework.displayName() + " (priority=" + framework.priority() + ")");
} catch (Exception e) {
LOG.severe(" ✗ Failed to install " + framework.frameworkId() + ": " + e.getMessage());
throw new RuntimeException("Failed to install compliance framework: " + framework.frameworkId(), e);
}
} else {
LOG.fine(" - Skipping " + framework.frameworkId() + " (not enabled)");
}
}
LOG.info("Successfully installed " + installedCount + " CloudForge FrameworkRules validators");
}
/**
* Auto-apply cdk-nag validation packs based on enabled compliance frameworks.
*
* <p>Maps framework names to appropriate cdk-nag rule packs:</p>
* <ul>
* <li><strong>HIPAA:</strong> HIPAASecurityChecks</li>
* <li><strong>PCI-DSS:</strong> PCIDSS321Checks</li>
* <li><strong>SOC2:</strong> AwsSolutionsChecks</li>
* <li><strong>Custom:</strong> AwsSolutionsChecks (fallback)</li>
* </ul>
*
* <p>The enforcement mode is determined by {@code complianceMode}:</p>
* <ul>
* <li><strong>enforce:</strong> Blocks synthesis on violations</li>
* <li><strong>advisory:</strong> Logs warnings only</li>
* </ul>
*
* @param ctx the system context containing deployment configuration
* @param enabledFrameworks set of enabled framework IDs (uppercase)
* @since 3.1.0
*/
private static void applyCdkNagValidation(SystemContext ctx, Set<String> enabledFrameworks) {
if (enabledFrameworks.isEmpty()) {
LOG.info("No frameworks enabled - skipping cdk-nag validation");
return;
}
boolean enforce = ctx.cfc.complianceMode() == ComplianceMode.ENFORCE;
LOG.info("Applying cdk-nag validation (mode=" + (enforce ? "enforce" : "advisory") + ")");
int appliedCount = 0;
for (String framework : enabledFrameworks) {
NagPack pack = mapFrameworkToNagPack(framework, enforce);
if (pack != null) {
Aspects.of(ctx.getNode().getRoot()).add(pack);
appliedCount++;
LOG.info(" ✓ Applied cdk-nag pack for " + framework);
}
}
LOG.info("Applied " + appliedCount + " cdk-nag validation packs");
}
/**
* Maps a compliance framework to its corresponding cdk-nag rule pack.
*
* @param framework the framework ID (uppercase)
* @param enforce true to enforce violations, false to log only
* @return the corresponding NagPack, or null if no mapping exists
* @since 3.1.0
*/
private static NagPack mapFrameworkToNagPack(String framework, boolean enforce) {
// Report formats for compliance auditing
var reportFormats = List.of(NagReportFormat.JSON, NagReportFormat.CSV);
return switch (framework) {
case "HIPAA" -> HIPAASecurityChecks.Builder.create()
.logIgnores(!enforce)
.reports(true)
.reportFormats(reportFormats)
.build();
case "PCI-DSS" -> PCIDSS321Checks.Builder.create()
.logIgnores(!enforce)
.reports(true)
.reportFormats(reportFormats)
.build();
case "SOC2" -> AwsSolutionsChecks.Builder.create()
.logIgnores(!enforce)
.reports(true)
.reportFormats(reportFormats)
.build();
// FEDRAMP: Handled by existing FedRampRules.java plugin only
// Not integrated with cdk-nag to avoid conflicts (future epic)
case "FEDRAMP", "FEDRAMPHIGH" -> {
LOG.info(" - Skipping cdk-nag for " + framework + " (uses existing FedRampRules.java)");
yield null;
}
// Custom frameworks: fallback to AWS Solutions best practices
default -> {
LOG.info(" - Applying AwsSolutionsChecks (fallback) for custom framework: " + framework);
yield AwsSolutionsChecks.Builder.create()
.logIgnores(!enforce)
.reports(true)
.reportFormats(reportFormats)
.build();
}
};
}
}