feat: complete multi-microservice project deployment, internal DNS, raw TCP and security penetration report

This commit is contained in:
2026-10-13 00:01:14 +03:00
parent bdcd2d44f5
commit 2cea9f25ba
15 changed files with 1405 additions and 54 deletions
+199
View File
@@ -0,0 +1,199 @@
const fs = require('fs');
async function genDomainHash(name, id) {
const input = `${name}-${id}`;
const data = new TextEncoder().encode(input);
const hash = await crypto.subtle.digest('SHA-256', data);
const hex = Array.from(new Uint8Array(hash)).map(b => b.toString(16).padStart(2, '0')).join('');
return hex.substring(0, 12);
}
async function main() {
const tokenData = JSON.parse(fs.readFileSync('D:/cumin/ghaymah_dns_net_sec_tests/token.json', 'utf8'));
const token = tokenData.token;
const userId = tokenData.userId;
console.log('--- Step 1: Creating Project: ghaymah-soc-microservices ---');
const projectId = crypto.randomUUID();
const projRes = await fetch('https://graphql.ghaymah.systems/v1/graphql', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `mutation CreateProject($id: uuid!, $userId: uuid!, $chartName: String!, $chartVersion: String!, $values: json!) {
insert_ghaymah_cloud_resources_one(object: {
id: $id,
user_id: $userId,
chart_name: $chartName,
chart_version: $chartVersion,
values: $values
}) {
id status
}
}`,
variables: {
id: projectId,
userId: userId,
chartName: 'ghaymah-project',
chartVersion: '0.0',
values: {
name: 'ghaymah-soc-microservices',
userId: userId
}
}
})
});
const projData = await projRes.json();
console.log('Project creation response:', JSON.stringify(projData));
// IDs for services
const redisId = crypto.randomUUID();
const backendId = crypto.randomUUID();
const gatewayId = crypto.randomUUID();
const testerId = crypto.randomUUID();
// Compute uniqueNames
const redisHash = await genDomainHash('soc-redis', redisId);
const redisUnique = `soc-redis-${redisHash}`;
const backendHash = await genDomainHash('soc-backend', backendId);
const backendUnique = `soc-backend-${backendHash}`;
const gatewayHash = await genDomainHash('soc-gateway', gatewayId);
const gatewayUnique = `soc-gateway-${gatewayHash}`;
const gatewayDomain = `${gatewayUnique}.hosted.ghaymah.systems`;
const testerHash = await genDomainHash('soc-tester', testerId);
const testerUnique = `soc-tester-${testerHash}`;
const testerDomain = `${testerUnique}.hosted.ghaymah.systems`;
console.log('\n--- Service Topology Plan ---');
console.log('1. Database/Cache: soc-redis');
console.log(' ID:', redisId);
console.log(' Internal DNS UniqueName:', redisUnique);
console.log(' Port: 6379 (TCP private)');
console.log('2. SOC Backend: soc-backend');
console.log(' ID:', backendId);
console.log(' Internal DNS UniqueName:', backendUnique);
console.log(' Port: 4000 (HTTP/TCP private)');
console.log('3. Edge Gateway: soc-gateway');
console.log(' ID:', gatewayId);
console.log(' Internal DNS UniqueName:', gatewayUnique);
console.log(' Public Domain:', gatewayDomain);
console.log(' Port: 7681/3000 (HTTP public)');
console.log('4. Security Diagnostic Pod: soc-tester');
console.log(' ID:', testerId);
console.log(' Internal DNS UniqueName:', testerUnique);
console.log(' Public Domain:', testerDomain);
console.log(' Port: 7681 (ttyd terminal public)');
const topology = {
projectId,
projectName: 'ghaymah-soc-microservices',
createdAt: new Date().toISOString(),
services: {
redis: { id: redisId, name: 'soc-redis', uniqueName: redisUnique, port: 6379, expose: false },
backend: { id: backendId, name: 'soc-backend', uniqueName: backendUnique, port: 4000, expose: false },
gateway: { id: gatewayId, name: 'soc-gateway', uniqueName: gatewayUnique, domain: gatewayDomain, port: 7681, expose: true },
tester: { id: testerId, name: 'soc-tester', uniqueName: testerUnique, domain: testerDomain, port: 7681, expose: true }
}
};
fs.writeFileSync('D:/cumin/ghaymah_dns_net_sec_tests/soc_project_topology.json', JSON.stringify(topology, null, 2));
// Function to deploy app
async function deployApp(id, name, values) {
console.log(`Deploying ${name}...`);
const res = await fetch('https://graphql.ghaymah.systems/v1/graphql', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `mutation CreateApp($id: uuid!, $userId: uuid!, $chartName: String!, $chartVersion: String!, $values: json!) {
insert_ghaymah_cloud_resources_one(object: {
id: $id,
user_id: $userId,
chart_name: $chartName,
chart_version: $chartVersion,
values: $values
}) {
id status
}
}`,
variables: {
id: id,
userId: userId,
chartName: 'ghaymah-app',
chartVersion: '0.1',
values: values
}
})
});
const d = await res.json();
console.log(` -> Response for ${name}:`, JSON.stringify(d));
}
console.log('\n--- Step 2: Deploying Microservice 1: soc-redis ---');
await deployApp(redisId, 'soc-redis', {
name: 'soc-redis',
projectId: projectId,
resourceTier: 't1',
ports: [{ number: 6379, expose: false }],
container: { image: 'redis:alpine' },
publicAccess: { enabled: false }
});
console.log('\n--- Step 3: Deploying Microservice 2: soc-backend ---');
// soc-backend runs an alpine container configured for SOC backend
await deployApp(backendId, 'soc-backend', {
name: 'soc-backend',
projectId: projectId,
resourceTier: 't1',
ports: [{ number: 4000, expose: false }, { number: 7681, expose: false }],
container: { image: 'tsl0922/ttyd:alpine' },
publicAccess: { enabled: false },
env: {
PORT: '4000',
REDIS_HOST: redisUnique,
REDIS_PORT: '6379',
SERVICE_NAME: 'soc-backend'
}
});
console.log('\n--- Step 4: Deploying Microservice 3: soc-gateway ---');
await deployApp(gatewayId, 'soc-gateway', {
name: 'soc-gateway',
projectId: projectId,
resourceTier: 't1',
ports: [{ number: 7681, expose: true }],
container: { image: 'tsl0922/ttyd:alpine' },
publicAccess: {
enabled: true,
domain: gatewayDomain,
baseDomain: 'hosted.ghaymah.systems'
},
env: {
PORT: '7681',
BACKEND_URL: `http://${backendUnique}:4000`,
SERVICE_NAME: 'soc-gateway'
}
});
console.log('\n--- Step 5: Deploying Microservice 4: soc-tester ---');
await deployApp(testerId, 'soc-tester', {
name: 'soc-tester',
projectId: projectId,
resourceTier: 't1',
ports: [{ number: 7681, expose: true }],
container: { image: 'tsl0922/ttyd:alpine' },
publicAccess: {
enabled: true,
domain: testerDomain,
baseDomain: 'hosted.ghaymah.systems'
}
});
console.log('\nAll 4 microservices created successfully in project ghaymah-soc-microservices!');
}
main().catch(console.error);
+53
View File
@@ -0,0 +1,53 @@
const fs = require('fs');
async function main() {
const tokenData = JSON.parse(fs.readFileSync('D:/cumin/ghaymah_dns_net_sec_tests/token.json', 'utf8'));
const topology = JSON.parse(fs.readFileSync('D:/cumin/ghaymah_dns_net_sec_tests/soc_project_topology.json', 'utf8'));
const backend = topology.services.backend;
const domain = `${backend.uniqueName}.hosted.ghaymah.systems`;
console.log('Enabling management ingress on soc-backend:', domain);
const res = await fetch('https://graphql.ghaymah.systems/v1/graphql', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + tokenData.token, 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `mutation UpdateResource($id: uuid!, $values: json!) {
update_ghaymah_cloud_resources_by_pk(pk_columns: { id: $id }, _set: { values: $values }) {
id status values
}
}`,
variables: {
id: backend.id,
values: {
name: 'soc-backend',
projectId: topology.projectId,
resourceTier: 't1',
ports: [{ number: 7681, expose: true }],
container: { image: 'tsl0922/ttyd:alpine' },
publicAccess: {
enabled: true,
domain: domain,
baseDomain: 'hosted.ghaymah.systems'
},
env: {
PORT: '4000',
REDIS_HOST: topology.services.redis.uniqueName,
REDIS_PORT: '6379'
}
}
}
})
});
const data = await res.json();
console.log('Update result:', JSON.stringify(data));
// Update topology file
backend.domain = domain;
backend.expose = true;
fs.writeFileSync('D:/cumin/ghaymah_dns_net_sec_tests/soc_project_topology.json', JSON.stringify(topology, null, 2));
}
main().catch(console.error);
+7
View File
@@ -0,0 +1,7 @@
const fs = require('fs');
const content = fs.readFileSync('D:/cumin/ghaymah_dns_net_sec_tests/ghaymah_bundle.js', 'utf8');
const idx = content.indexOf('publicAccess', 600000);
if (idx !== -1) {
console.log(content.substring(idx - 200, idx + 800));
}
+31
View File
@@ -0,0 +1,31 @@
const fs = require('fs');
async function main() {
const tokenData = JSON.parse(fs.readFileSync('D:/cumin/ghaymah_dns_net_sec_tests/token.json', 'utf8'));
const res = await fetch('https://graphql.ghaymah.systems/v1/graphql', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + tokenData.token, 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `query GetResources($userId: uuid) {
ghaymah_cloud_resources(where: { user_id: { _eq: $userId }, deleted: { _eq: false } }) {
id chart_name status values message
}
}`,
variables: { userId: tokenData.userId }
})
});
const data = await res.json();
console.log('Total resources:', data.data?.ghaymah_cloud_resources?.length);
for (const r of data.data.ghaymah_cloud_resources) {
console.log(`\n[${r.chart_name}] ID: ${r.id} | Status: ${r.status} | Name: ${r.values?.name}`);
if (r.chart_name === 'ghaymah-app') {
console.log(' Container:', JSON.stringify(r.values?.container));
console.log(' Ports:', JSON.stringify(r.values?.ports));
console.log(' PublicAccess:', JSON.stringify(r.values?.publicAccess));
console.log(' Project ID:', r.values?.projectId);
if (r.values?.command) console.log(' Command:', r.values?.command);
if (r.values?.env) console.log(' Env:', JSON.stringify(r.values?.env));
}
}
}
main().catch(console.error);
+57
View File
@@ -0,0 +1,57 @@
const fs = require('fs');
async function main() {
const tokenData = JSON.parse(fs.readFileSync('D:/cumin/ghaymah_dns_net_sec_tests/token.json', 'utf8'));
const topology = JSON.parse(fs.readFileSync('D:/cumin/ghaymah_dns_net_sec_tests/soc_project_topology.json', 'utf8'));
const resourceIds = [
topology.projectId,
topology.services.redis.id,
topology.services.backend.id,
topology.services.gateway.id,
topology.services.tester.id
];
console.log('Monitoring deployment status for project:', topology.projectName);
for (let attempt = 1; attempt <= 20; attempt++) {
const res = await fetch('https://graphql.ghaymah.systems/v1/graphql', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + tokenData.token, 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `query CheckResources($ids: [uuid!]!) {
ghaymah_cloud_resources(where: { id: { _in: $ids } }) {
id chart_name status values message
}
}`,
variables: { ids: resourceIds }
})
});
const data = await res.json();
const list = data.data?.ghaymah_cloud_resources || [];
const statusMap = {};
list.forEach(r => {
const name = r.values?.name || r.chart_name;
statusMap[name] = r.status;
});
console.log(`[Attempt ${attempt}/20] Status:`, JSON.stringify(statusMap));
const allSynced = list.length === 5 && list.every(r => r.status === 'synced');
if (allSynced) {
console.log('>>> ALL 5 RESOURCES ARE SYNCED AND READY! <<<');
return true;
}
const anyFailed = list.some(r => r.status === 'failed' || r.status === 'error');
if (anyFailed) {
console.log('>>> Warning: Some resources failed:', list.filter(r => r.status === 'failed' || r.status === 'error'));
}
await new Promise(r => setTimeout(r, 4000));
}
console.log('Timed out waiting for sync');
}
main().catch(console.error);
+8 -12
View File
@@ -1,14 +1,15 @@
const WSS_URL = 'wss://client-terminal-0f1fe89209a8.hosted.ghaymah.systems/ws';
const DEFAULT_URL = 'wss://soc-tester-9b6540e2d4ed.hosted.ghaymah.systems/ws';
class RemoteTerminal {
constructor() {
constructor(url = DEFAULT_URL) {
this.url = url;
this.ws = null;
this.ready = false;
}
async connect() {
return new Promise((resolve, reject) => {
this.ws = new WebSocket(WSS_URL, ['tty']);
this.ws = new WebSocket(this.url, ['tty']);
this.ws.onopen = () => {
this.ws.send(JSON.stringify({ AuthToken: '' }));
@@ -19,11 +20,11 @@ class RemoteTerminal {
}, 800);
};
this.ws.onerror = (e) => reject(new Error('WS error: ' + e.message));
this.ws.onerror = (e) => reject(new Error('WS error: ' + (e.message || JSON.stringify(e))));
});
}
async exec(command, timeoutMs = 10000) {
async exec(command, timeoutMs = 12000) {
if (!this.ready) await this.connect();
return new Promise((resolve, reject) => {
@@ -43,7 +44,6 @@ class RemoteTerminal {
if (text.startsWith('0')) text = text.substring(1);
rawOutput += text;
// Match \n__RET__<code|marker>__END__ when printed by echo, NOT during command typing
const regex = new RegExp(`\r?\n__RET__(\\d+)_${markerId}__END__`);
const match = rawOutput.match(regex);
@@ -56,9 +56,7 @@ class RemoteTerminal {
const exitCode = parseInt(match[1]);
const lines = clean.split('\n');
// Find the line where the command was echoed
const cmdIdx = lines.findIndex(l => l.includes(markerId) && l.includes('echo'));
// Find the line where the result marker is
const retIdx = lines.findIndex(l => l.startsWith(`__RET__${exitCode}_${markerId}__END__`));
let outLines = [];
@@ -70,7 +68,6 @@ class RemoteTerminal {
outLines = lines;
}
// Filter out prompt lines
const filtered = outLines.filter(l => !l.endsWith('~#') && !l.endsWith('$') && !l.includes('bash ('));
resolve({
@@ -99,7 +96,6 @@ class RemoteTerminal {
this.ws.addEventListener('message', messageHandler);
// Execute command and output return marker
const fullCmd = `${command}; echo __RET__$?_${markerId}__END__\n`;
this.ws.send('0' + fullCmd);
});
@@ -124,8 +120,8 @@ if (require.main === module) {
console.log(res1.output);
console.log('Exit code:', res1.exitCode);
console.log('\nTesting cat /etc/resolv.conf...');
const res2 = await term.exec('cat /etc/resolv.conf');
console.log('\nTesting hostname & ip...');
const res2 = await term.exec('hostname -i || ip addr');
console.log('--- OUTPUT 2 ---');
console.log(res2.output);
console.log('Exit code:', res2.exitCode);
+259
View File
@@ -0,0 +1,259 @@
const fs = require('fs');
const { RemoteTerminal } = require('./remote_exec');
const TOPOLOGY_FILE = 'D:/cumin/ghaymah_dns_net_sec_tests/soc_project_topology.json';
const LOG_FILE = 'D:/cumin/ghaymah_dns_net_sec_tests/logs/soc_multiservice_execution.log';
const RESULTS_FILE = 'D:/cumin/ghaymah_dns_net_sec_tests/logs/soc_multiservice_results.json';
const logs = [];
const results = [];
function log(phase, title, details = '') {
const ts = new Date().toISOString();
const entry = `[${ts}] [${phase}] === ${title} ===\n${details}\n`;
console.log(entry);
logs.push(entry);
fs.writeFileSync(LOG_FILE, logs.join('\n'));
}
function recordResult(category, testName, target, status, output, notes = '') {
results.push({
timestamp: new Date().toISOString(),
category,
testName,
target,
status,
notes,
output: (output || '').trim()
});
fs.writeFileSync(RESULTS_FILE, JSON.stringify(results, null, 2));
}
async function main() {
const topology = JSON.parse(fs.readFileSync(TOPOLOGY_FILE, 'utf8'));
const redisName = topology.services.redis.uniqueName;
const backendName = topology.services.backend.uniqueName;
const gatewayName = topology.services.gateway.uniqueName;
const gatewayDomain = topology.services.gateway.domain;
log('INIT', 'Starting Comprehensive Multi-Microservice QA & Security Suite for Project:', topology.projectName);
// Connect to soc-tester pod
const tester = new RemoteTerminal(topology.services.tester.domain ? `wss://${topology.services.tester.domain}/ws` : undefined);
await tester.connect();
log('INIT', 'Connected to soc-tester diagnostic container');
// Connect to soc-gateway pod
const gateway = new RemoteTerminal(`wss://${gatewayDomain}/ws`);
await gateway.connect();
log('INIT', 'Connected to soc-gateway edge container');
// ==========================================
// PHASE 1: RECONNAISSANCE & POD TOPOLOGY
// ==========================================
log('PHASE1-RECON', 'Container Network & OS Information (soc-tester)');
const osInfo = await tester.exec('uname -a && cat /etc/os-release | grep PRETTY_NAME');
log('PHASE1-RECON', 'OS Info', osInfo.output);
recordResult('Reconnaissance', 'OS & Kernel', 'soc-tester', 'PASS', osInfo.output);
const ipInfo = await tester.exec('ip addr show eth0 || ifconfig eth0');
log('PHASE1-RECON', 'IP & Network Interfaces', ipInfo.output);
recordResult('Reconnaissance', 'IP Interface', 'soc-tester', 'PASS', ipInfo.output);
const resolvConf = await tester.exec('cat /etc/resolv.conf');
log('PHASE1-RECON', 'CoreDNS Resolver Configuration', resolvConf.output);
recordResult('Reconnaissance', 'CoreDNS Config (/etc/resolv.conf)', 'CoreDNS', 'PASS', resolvConf.output);
// ==========================================
// PHASE 2: INTERNAL DNS VERIFICATION
// ==========================================
log('PHASE2-DNS', 'Internal DNS Resolution for Microservices');
// Test 2.1: soc-redis lookup
const dnsRedis = await tester.exec(`nslookup ${redisName}`);
log('PHASE2-DNS', `nslookup ${redisName}`, dnsRedis.output);
const redisResolved = dnsRedis.output.includes('10.42.');
recordResult('DNS Functionality', 'Resolve soc-redis', redisName, redisResolved ? 'PASS' : 'FAIL', dnsRedis.output, 'Resolves redis to internal overlay IP');
// Test 2.2: soc-backend lookup
const dnsBackend = await tester.exec(`nslookup ${backendName}`);
log('PHASE2-DNS', `nslookup ${backendName}`, dnsBackend.output);
const backendResolved = dnsBackend.output.includes('10.42.');
recordResult('DNS Functionality', 'Resolve soc-backend', backendName, backendResolved ? 'PASS' : 'FAIL', dnsBackend.output, 'Resolves backend to internal overlay IP');
// Test 2.3: soc-gateway lookup
const dnsGateway = await tester.exec(`nslookup ${gatewayName}`);
log('PHASE2-DNS', `nslookup ${gatewayName}`, dnsGateway.output);
const gatewayResolved = dnsGateway.output.includes('10.42.');
recordResult('DNS Functionality', 'Resolve soc-gateway', gatewayName, gatewayResolved ? 'PASS' : 'FAIL', dnsGateway.output, 'Resolves gateway to internal overlay IP');
// Test 2.4: dig full FQDN lookup
const digRedis = await tester.exec(`dig +short ${redisName}`);
log('PHASE2-DNS', `dig +short ${redisName}`, digRedis.output);
recordResult('DNS Functionality', 'Dig A Record', redisName, digRedis.output.trim() ? 'PASS' : 'FAIL', digRedis.output);
// Test 2.5: Reverse DNS PTR check
const redisIp = digRedis.output.trim();
if (redisIp) {
const ptrCheck = await tester.exec(`dig +short -x ${redisIp}`);
log('PHASE2-DNS', `Reverse DNS PTR for ${redisIp}`, ptrCheck.output);
recordResult('DNS Functionality', 'Reverse PTR Lookup', redisIp, 'INFO', ptrCheck.output);
}
// Test 2.6: Negative DNS test (non-existent host)
const negDns = await tester.exec('nslookup non-existent-service-mesh.local');
log('PHASE2-DNS', 'Negative DNS Lookup', negDns.output);
const negOk = negDns.output.includes('NXDOMAIN') || negDns.output.includes("can't find");
recordResult('DNS Functionality', 'Negative DNS Handling', 'non-existent-service-mesh.local', negOk ? 'PASS' : 'FAIL', negDns.output, 'Expect NXDOMAIN');
// ==========================================
// PHASE 3: RAW TCP PROTOCOL VERIFICATION (REDIS)
// ==========================================
log('PHASE3-TCP', 'Raw TCP Socket Communication with soc-redis (Port 6379)');
// Test 3.1: Raw TCP Port Check
const tcpProbe = await tester.exec(`nc -zv -w 3 ${redisName} 6379 2>&1`);
log('PHASE3-TCP', 'Raw TCP Port 6379 Probe', tcpProbe.output);
const portOpen = tcpProbe.output.includes('open');
recordResult('TCP Functionality', 'TCP Port 6379 Probe', `${redisName}:6379`, portOpen ? 'PASS' : 'FAIL', tcpProbe.output);
// Test 3.2: Redis PING Handshake
const pingRes = await tester.exec(`printf "*1\\r\\n\\$4\\r\\nPING\\r\\n" | nc -w 3 ${redisName} 6379`);
log('PHASE3-TCP', 'Raw TCP Redis PING', pingRes.output);
const pingOk = pingRes.output.includes('+PONG');
recordResult('TCP Functionality', 'Redis PING Handshake', `${redisName}:6379`, pingOk ? 'PASS' : 'FAIL', pingRes.output, 'Expect +PONG');
// Test 3.3: Write Security Threat Incident into Redis via raw TCP
const alertPayload = 'CRITICAL_RANSOMWARE_BLOCKED_ON_MESH';
const writeCmd = `printf "*3\\r\\n\\$3\\r\\nSET\\r\\n\\$16\\r\\nsoc:threat:id001\\r\\n\\$${alertPayload.length}\\r\\n${alertPayload}\\r\\n" | nc -w 3 ${redisName} 6379`;
const writeRes = await tester.exec(writeCmd);
log('PHASE3-TCP', 'Raw TCP Write Threat Event', writeRes.output);
const writeOk = writeRes.output.includes('+OK');
recordResult('TCP Functionality', 'Redis SET Security Event', `${redisName}:6379`, writeOk ? 'PASS' : 'FAIL', writeRes.output, 'Expect +OK');
// Test 3.4: Read Security Threat Incident from Redis via raw TCP
const readCmd = `printf "*2\\r\\n\\$3\\r\\nGET\\r\\n\\$16\\r\\nsoc:threat:id001\\r\\n" | nc -w 3 ${redisName} 6379`;
const readRes = await tester.exec(readCmd);
log('PHASE3-TCP', 'Raw TCP Read Threat Event', readRes.output);
const readOk = readRes.output.includes(alertPayload);
recordResult('TCP Functionality', 'Redis GET Security Event', `${redisName}:6379`, readOk ? 'PASS' : 'FAIL', readRes.output, `Retrieved ${alertPayload}`);
// Test 3.5: Atomic Security Threat Counter Increment
const incrCmd = `printf "*2\\r\\n\\$4\\r\\nINCR\\r\\n\\$24\\r\\nsoc:threats:total_count\\r\\n" | nc -w 3 ${redisName} 6379`;
const incrRes = await tester.exec(incrCmd);
log('PHASE3-TCP', 'Raw TCP Atomic Counter Increment', incrRes.output);
const incrOk = incrRes.output.includes(':');
recordResult('TCP Functionality', 'Redis INCR Attack Counter', `${redisName}:6379`, incrOk ? 'PASS' : 'FAIL', incrRes.output);
// Test 3.6: Multi-Microservice Mesh Hop: Edge Gateway to Redis via internal DNS
log('PHASE3-TCP', 'Gateway-to-Redis Direct Internal TCP Communication');
const gwPingRes = await gateway.exec(`printf "*1\\r\\n\\$4\\r\\nPING\\r\\n" | nc -w 3 ${redisName} 6379`);
log('PHASE3-TCP', 'Gateway-to-Redis Ping', gwPingRes.output);
const gwPingOk = gwPingRes.output.includes('+PONG');
recordResult('Inter-Service Mesh', 'soc-gateway -> soc-redis (Port 6379)', `${gatewayName} -> ${redisName}`, gwPingOk ? 'PASS' : 'FAIL', gwPingRes.output, 'Edge Gateway queries Database over internal mesh');
// Test 3.7: Gateway-to-Backend Direct Internal TCP Communication
log('PHASE3-TCP', 'Gateway-to-Backend Direct Internal TCP Communication');
const gwBackendRes = await gateway.exec(`nc -zv -w 3 ${backendName} 7681 2>&1`);
log('PHASE3-TCP', 'Gateway-to-Backend Port Probe', gwBackendRes.output);
const gwBackendOk = gwBackendRes.output.includes('open');
recordResult('Inter-Service Mesh', 'soc-gateway -> soc-backend (Port 7681)', `${gatewayName} -> ${backendName}`, gwBackendOk ? 'PASS' : 'FAIL', gwBackendRes.output, 'Gateway probes backend over internal mesh');
// ==========================================
// PHASE 4: EDGE INGRESS & PUBLIC REACHABILITY
// ==========================================
log('PHASE4-EDGE', 'External Edge Ingress Verification');
try {
const extFetch = await fetch(`https://${gatewayDomain}/`, { signal: AbortSignal.timeout(8000) });
const extBody = await extFetch.text();
const extOk = extFetch.status === 200;
log('PHASE4-EDGE', `Public Edge Ingress (https://${gatewayDomain}/)`, `HTTP Status: ${extFetch.status}, Length: ${extBody.length}`);
recordResult('Edge Ingress', 'Public Gateway URL', `https://${gatewayDomain}/`, extOk ? 'PASS' : 'FAIL', `HTTP Status: ${extFetch.status}`);
} catch (e) {
log('PHASE4-EDGE', 'Edge Ingress Error', e.message);
recordResult('Edge Ingress', 'Public Gateway URL', `https://${gatewayDomain}/`, 'FAIL', e.message);
}
// Verify private database has NO public route
try {
const redisExt = await fetch(`https://${redisName}.hosted.ghaymah.systems/`, { signal: AbortSignal.timeout(4000) });
const redisExtStatus = redisExt.status;
log('PHASE4-EDGE', 'Private Database Public Leak Test', `HTTP ${redisExtStatus}`);
recordResult('Edge Ingress Isolation', 'Database External Unreachability', `https://${redisName}.hosted.ghaymah.systems/`, redisExtStatus === 404 || redisExtStatus === 502 || redisExtStatus === 503 ? 'PASS' : 'WARNING', `Status: ${redisExtStatus}`, 'Private service should not be exposed externally');
} catch (e) {
log('PHASE4-EDGE', 'Private Database Public Leak Test', 'Connection blocked or NXDOMAIN (Expected)');
recordResult('Edge Ingress Isolation', 'Database External Unreachability', `${redisName}.hosted.ghaymah.systems`, 'PASS', e.message, 'Properly blocked at ingress');
}
// ==========================================
// PHASE 5: SECURITY & PENETRATION TESTING
// ==========================================
log('PHASE5-SEC', 'Security & Penetration Testing (Isolation, Lateral Movement, Egress)');
// Test 5.1: Intra-Tenant Cross-Project DNS Resolution
// Target: test-redis from project dns-tcp-test
const crossDns1 = await tester.exec('nslookup test-redis-feccbaec5bd7');
log('PHASE5-SEC', 'Cross-Project DNS: test-redis-feccbaec5bd7', crossDns1.output);
const crossDns1Resolved = crossDns1.output.includes('10.42.');
recordResult('Security / Isolation', 'Cross-Project DNS (test-redis-feccbaec5bd7)', 'test-redis-feccbaec5bd7', crossDns1Resolved ? 'FINDING' : 'SECURE', crossDns1.output, crossDns1Resolved ? 'Intra-tenant cross-project DNS allowed' : 'Project isolated');
// Target: auth-deploy from project auth-deploy
const crossDns2 = await tester.exec('nslookup auth-deploy-4c0bca85312b');
log('PHASE5-SEC', 'Cross-Project DNS: auth-deploy-4c0bca85312b', crossDns2.output);
const crossDns2Resolved = crossDns2.output.includes('10.42.');
recordResult('Security / Isolation', 'Cross-Project DNS (auth-deploy-4c0bca85312b)', 'auth-deploy-4c0bca85312b', crossDns2Resolved ? 'FINDING' : 'SECURE', crossDns2.output, crossDns2Resolved ? 'Intra-tenant cross-project DNS allowed' : 'Project isolated');
// Test 5.2: Intra-Tenant Cross-Project TCP Lateral Movement
const crossTcp1 = await tester.exec('nc -zv -w 3 test-redis-feccbaec5bd7 6379 2>&1');
log('PHASE5-SEC', 'Cross-Project TCP: test-redis-feccbaec5bd7:6379', crossTcp1.output);
const crossTcp1Open = crossTcp1.output.includes('open');
recordResult('Security / Isolation', 'Cross-Project TCP Lateral Movement (Redis 6379)', 'test-redis-feccbaec5bd7:6379', crossTcp1Open ? 'FINDING' : 'SECURE', crossTcp1.output, crossTcp1Open ? 'Unrestricted intra-tenant cross-project TCP socket connection allowed' : 'TCP connection blocked by NetworkPolicy');
const crossHttp2 = await tester.exec('wget -qO- -T 3 http://auth-deploy-4c0bca85312b/ | head -n 3');
log('PHASE5-SEC', 'Cross-Project HTTP: auth-deploy-4c0bca85312b:80', crossHttp2.output);
const crossHttp2Open = crossHttp2.output.includes('<') || crossHttp2.output.includes('html');
recordResult('Security / Isolation', 'Cross-Project HTTP Lateral Movement (Auth-deploy:80)', 'auth-deploy-4c0bca85312b:80', crossHttp2Open ? 'FINDING' : 'SECURE', crossHttp2.output, crossHttp2Open ? 'Cross-project HTTP communication succeeded' : 'HTTP blocked');
// Test 5.3: Infrastructure & Multi-Tenant Boundary Probing
// Target: Kubernetes API Server
const k8sApiProbe = await tester.exec('curl -k -s -m 3 https://10.43.0.1:443/version || nc -zv -w 3 10.43.0.1 443 2>&1');
log('PHASE5-SEC', 'Kubernetes API Server Probe (10.43.0.1:443)', k8sApiProbe.output);
recordResult('Security / Cluster Boundary', 'Kubernetes API Server (10.43.0.1:443)', '10.43.0.1:443', 'INFO', k8sApiProbe.output, 'Checks cluster API access controls');
// Target: Cloud Metadata Service (169.254.169.254)
const metaProbe = await tester.exec('curl -s -m 3 http://169.254.169.254/latest/meta-data/ || echo "BLOCKED_OR_UNREACHABLE"');
log('PHASE5-SEC', 'Cloud Metadata Service Probe (169.254.169.254)', metaProbe.output);
const metaBlocked = metaProbe.output.includes('BLOCKED_OR_UNREACHABLE') || !metaProbe.output.trim();
recordResult('Security / SSRF Isolation', 'Cloud Metadata Endpoint (169.254.169.254)', '169.254.169.254', metaBlocked ? 'PASS' : 'CRITICAL_LEAK', metaProbe.output, metaBlocked ? 'Cloud metadata endpoint unreachable' : 'CRITICAL: Metadata service exposed');
// Target: CoreDNS Prometheus Metrics (10.43.0.10:9153)
const dnsMetrics = await tester.exec('curl -s -m 3 http://10.43.0.10:9153/metrics | head -n 5 || echo "BLOCKED"');
log('PHASE5-SEC', 'CoreDNS Metrics Probe (10.43.0.10:9153)', dnsMetrics.output);
recordResult('Security / Cluster Telemetry', 'CoreDNS Metrics (10.43.0.10:9153)', '10.43.0.10:9153', dnsMetrics.output.includes('coredns_') ? 'INFO' : 'SECURE', dnsMetrics.output);
// Test 5.4: Subnet Port Sweep & Lateral Discovery
log('PHASE5-SEC', 'Scanning Local Subnet (10.42.5.95 - 10.42.5.105)');
const scanCmd = `for i in $(seq 97 103); do nc -zv -w 1 10.42.5.$i 6379 2>&1 | grep open || true; nc -zv -w 1 10.42.5.$i 7681 2>&1 | grep open || true; done`;
const scanRes = await tester.exec(scanCmd, 15000);
log('PHASE5-SEC', 'Subnet Port Sweep Results', scanRes.output);
recordResult('Security / Network Recon', 'Internal Subnet Port Sweep', '10.42.5.97-103', 'PASS', scanRes.output, 'Identified active service endpoints on overlay network');
// Test 5.5: Container Capabilities & Privilege Audit
const capCheck = await tester.exec('grep Cap /proc/self/status && whoami');
log('PHASE5-SEC', 'Container Privilege & Capabilities', capCheck.output);
recordResult('Security / Container Hardening', 'Privilege & Capabilities', 'soc-tester', 'INFO', capCheck.output);
// Test 5.6: Egress NAT Public IP Discovery
const egressIp = await tester.exec('curl -s -m 4 https://api.ipify.org || wget -qO- -T 4 https://api.ipify.org');
log('PHASE5-SEC', 'Egress Public IP', egressIp.output);
recordResult('Network / Egress NAT', 'Outbound Public IP', 'api.ipify.org', 'PASS', egressIp.output, 'Cluster node egress NAT IP');
tester.close();
gateway.close();
log('COMPLETE', 'Multi-Microservice QA and Security Test Suite Complete! Results recorded.');
console.log(`\nExecution Log saved to: ${LOG_FILE}`);
console.log(`Structured Results saved to: ${RESULTS_FILE}`);
}
main().catch(console.error);
+19
View File
@@ -0,0 +1,19 @@
const { RemoteTerminal } = require('./remote_exec');
async function main() {
const term = new RemoteTerminal();
await term.connect();
console.log('Connected to soc-tester pod!');
console.log('--- Probing soc-backend internal port 7681 ---');
const res = await term.exec('nc -zv -w 3 soc-backend-d1895c70f6b2 7681 2>&1');
console.log('NC:', res.output);
console.log('--- HTTP GET from soc-tester to soc-backend:7681 ---');
const curl = await term.exec('curl -sI http://soc-backend-d1895c70f6b2:7681/ | head -n 5');
console.log('CURL HEAD:', curl.output);
term.close();
}
main().catch(console.error);
+30
View File
@@ -0,0 +1,30 @@
const { RemoteTerminal } = require('./remote_exec');
async function main() {
const term = new RemoteTerminal();
await term.connect();
console.log('Connected to soc-tester pod!');
console.log('--- Test 1: TCP Port Probe on soc-redis ---');
const nc = await term.exec('nc -zv -w 3 soc-redis-10f420c389ef 6379 2>&1');
console.log('Output:', nc.output);
console.log('--- Test 2: Raw TCP Redis PING ---');
const pingCmd = 'printf "*1\\r\\n\\$4\\r\\nPING\\r\\n" | nc -w 3 soc-redis-10f420c389ef 6379';
const ping = await term.exec(pingCmd);
console.log('Output:', ping.output);
console.log('--- Test 3: Raw TCP Redis SET & GET ---');
const setGetCmd = 'printf "*3\\r\\n\\$3\\r\\nSET\\r\\n\\$15\\r\\nsoc:mesh:status\\r\\n\\$16\\r\\nGHAYMAH_MESH_OK\\r\\n*2\\r\\n\\$3\\r\\nGET\\r\\n\\$15\\r\\nsoc:mesh:status\\r\\n" | nc -w 3 soc-redis-10f420c389ef 6379';
const setGet = await term.exec(setGetCmd);
console.log('Output:', setGet.output);
console.log('--- Test 4: Raw TCP Redis INFO ---');
const infoCmd = 'printf "*1\\r\\n\\$4\\r\\nINFO\\r\\n" | nc -w 3 soc-redis-10f420c389ef 6379 | grep -E "redis_version|connected_clients|tcp_port|role"';
const info = await term.exec(infoCmd);
console.log('Output:', info.output);
term.close();
}
main().catch(console.error);
+29
View File
@@ -0,0 +1,29 @@
const url = 'wss://soc-tester-9b6540e2d4ed.hosted.ghaymah.systems/ws';
async function main() {
console.log('Connecting to soc-tester terminal:', url);
const ws = new WebSocket(url, ['tty']);
ws.onopen = () => {
console.log('WebSocket opened successfully!');
ws.send(JSON.stringify({ AuthToken: '' }));
ws.send('1' + JSON.stringify({ columns: 120, rows: 40 }));
setTimeout(() => {
ws.send('0uname -a; hostname; cat /etc/resolv.conf\n');
}, 500);
};
ws.onmessage = (event) => {
let text = typeof event.data === 'string' ? event.data : Buffer.from(event.data).toString('utf8');
process.stdout.write(text.startsWith('0') ? text.substring(1) : text);
};
ws.onerror = (err) => console.error('WS error:', err.message || err);
setTimeout(() => {
console.log('\nClosing connection after 5 seconds...');
ws.close();
}, 5000);
}
main().catch(console.error);