Files
boc/terraform/discovery/drift-detection.mjs
T
Bernt 05ed037fe8 pilot.landvex.com: HTTPS + Full Stack Verified
- DNS: pilot.landvex.com -> 16.170.83.169
- TLS: Let's Encrypt certificate (expires 2026-09-30)
- Nginx: reverse proxy with SSL termination
- API: https://pilot.landvex.com/api/v1/missions
- UI: https://pilot.landvex.com/
- Upload: POST /api/v1/missions/import (multipart/form-data)

Verified:
 https://pilot.landvex.com/health
 https://pilot.landvex.com/version
 https://pilot.landvex.com/api/v1/missions (list)
 https://pilot.landvex.com/api/v1/missions/:id (get)
 POST /api/v1/missions/import (video upload)
 UI loads with title 'LandveX Intelligence Lab'

Next: Pilot 001 — Break the system!
2026-07-02 17:34:19 +00:00

176 lines
5.1 KiB
JavaScript

#!/usr/bin/env node
// ═══════════════════════════════════════════════════════════════════════════
// Infrastructure Drift Detection Engine
// Jämför Terraform-konfiguration med verklig AWS-miljö
// ═══════════════════════════════════════════════════════════════════════════
import { readFileSync } from 'fs';
class DriftDetectionEngine {
constructor(terraformDir, discoveryDir) {
this.terraformDir = terraformDir;
this.discoveryDir = discoveryDir;
this.findings = [];
}
/**
* Ladda Terraform-resurser från .tf-filer
*/
loadTerraformResources() {
// TODO: Parsa .tf-filer (kräver HCL-parser)
return {
aws_instance: ['aamos-ledger'],
aws_iam_role: ['ledger_ec2'],
aws_security_group: ['ledger'],
aws_secretsmanager_secret: ['ledger_jwt', 'ledger_internal', 'ledger_db', 'ledger_redis']
};
}
/**
* Ladda AWS-resurser från discovery JSON
*/
loadAWSResources() {
const resources = {};
try {
const ec2 = JSON.parse(readFileSync(`${this.discoveryDir}/ec2-instances.json`, 'utf8'));
resources.ec2 = ec2.Reservations?.flatMap(r => r.Instances?.map(i => ({
id: i.InstanceId,
type: i.InstanceType,
state: i.State?.Name,
tags: i.Tags
}))) || [];
} catch {
resources.ec2 = [];
}
try {
const rds = JSON.parse(readFileSync(`${this.discoveryDir}/rds-instances.json`, 'utf8'));
resources.rds = rds.DBInstances?.map(db => ({
id: db.DBInstanceIdentifier,
engine: db.Engine,
status: db.DBInstanceStatus
})) || [];
} catch {
resources.rds = [];
}
try {
const sg = JSON.parse(readFileSync(`${this.discoveryDir}/security-groups.json`, 'utf8'));
resources.security_groups = sg.SecurityGroups?.map(sg => ({
id: sg.GroupId,
name: sg.GroupName,
description: sg.Description
})) || [];
} catch {
resources.security_groups = [];
}
try {
const secrets = JSON.parse(readFileSync(`${this.discoveryDir}/secrets.json`, 'utf8'));
resources.secrets = secrets.SecretList?.map(s => ({
name: s.Name,
rotation: s.RotationEnabled
})) || [];
} catch {
resources.secrets = [];
}
return resources;
}
/**
* Detektera drift
*/
detect() {
const terraform = this.loadTerraformResources();
const aws = this.loadAWSResources();
// 1. Resurser i AWS som inte finns i Terraform
for (const ec2 of aws.ec2) {
const inTerraform = terraform.aws_instance?.some(name =>
ec2.tags?.some(t => t.Key === 'Name' && t.Value.includes(name))
);
if (!inTerraform) {
this.findings.push({
type: 'DRIFT',
severity: 'HIGH',
category: 'Orphaned Resource',
description: `EC2 ${ec2.id} finns i AWS men inte i Terraform`,
terraform: null,
aws: ec2,
action: 'Import or remove'
});
}
}
// 2. Resurser i Terraform som inte finns i AWS
for (const sg of terraform.aws_security_group || []) {
const inAWS = aws.security_groups?.some(a =>
a.name?.includes(sg)
);
if (!inAWS) {
this.findings.push({
type: 'DRIFT',
severity: 'MEDIUM',
category: 'Missing Resource',
description: `Security Group ${sg} finns i Terraform men inte i AWS`,
terraform: sg,
aws: null,
action: 'Create or update Terraform'
});
}
}
// 3. Secrets utan rotation
for (const secret of aws.secrets || []) {
if (!secret.rotation) {
this.findings.push({
type: 'DRIFT',
severity: 'CRITICAL',
category: 'Security',
description: `Secret ${secret.name} har ingen rotation`,
terraform: null,
aws: secret,
action: 'Enable rotation (STOP-013)'
});
}
}
return this.findings;
}
/**
* Generera rapport
*/
report() {
const findings = this.detect();
return {
summary: {
total: findings.length,
critical: findings.filter(f => f.severity === 'CRITICAL').length,
high: findings.filter(f => f.severity === 'HIGH').length,
medium: findings.filter(f => f.severity === 'MEDIUM').length,
low: findings.filter(f => f.severity === 'LOW').length
},
findings,
generatedAt: new Date().toISOString()
};
}
}
// CLI
if (process.argv[1] === new URL(import.meta.url).pathname) {
const engine = new DriftDetectionEngine(
'/home/bernt/.openclaw/workspace/terraform/aamos-ledger',
'/home/bernt/.openclaw/workspace/terraform/discovery'
);
console.log(JSON.stringify(engine.report(), null, 2));
}
export { DriftDetectionEngine };