@iota-big3/sdk-security
Version:
Advanced security features including zero trust, quantum-safe crypto, and ML threat detection
515 lines (514 loc) • 17.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServiceMeshIntegration = void 0;
const events_1 = require("events");
const grpc = __importStar(require("@grpc/grpc-js"));
const protoLoader = __importStar(require("@grpc/proto-loader"));
const crypto = __importStar(require("crypto"));
class ServiceMeshIntegration extends events_1.EventEmitter {
constructor(config, logger) {
super();
this.policies = new Map();
this.config = config;
this.logger = logger;
this.initializeGrpcClient();
this.startCertificateRotation();
}
initializeGrpcClient() {
try {
const packageDefinition = protoLoader.loadSync(this.getProtoPath(), {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true });
const proto = grpc.loadPackageDefinition(packageDefinition);
const ServiceClass = this.getServiceClass(proto);
this.grpcClient = new ServiceClass(this?.config?.controlPlaneUrl, grpc?.credentials?.createSsl());
this?.logger?.info('Service mesh gRPC client initialized', {
type: this.config.type,
url: this?.config?.controlPlaneUrl
});
}
catch (_error) {
this?.logger?.error('Failed to initialize gRPC client', error);
throw error;
}
}
getProtoPath() {
switch (this.config.type) {
case 'istio':
return 'protos/istio/security/v1beta1/authorization.proto';
case 'linkerd':
return 'protos/linkerd/policy/v1beta1/policy.proto';
default:
throw new Error(`Unsupported service mesh type: ${this.config.type}`);
}
}
getServiceClass(proto) {
switch (this.config.type) {
case 'istio':
return proto?.istio?.security.v1beta1.Authorization;
case 'linkerd':
return proto?.linkerd?.policy.v1beta1.Policy;
default:
throw new Error(`Unsupported service mesh type: ${this.config.type}`);
}
}
// Generate SPIFFE ID for service
generateSpiffeId(serviceName, namespace) {
const ns = namespace || this?.config?.namespace || 'default';
const trustDomain = this?.config?.trustDomain || 'cluster.local';
return `spiffe://${trustDomain}/ns/${ns}/sa/${serviceName}`;
}
// Register service with mesh
async registerService(serviceName, namespace) {
try {
const spiffeId = this.generateSpiffeId(serviceName, namespace);
const { certificate, privateKey } = await this.generateCertificate(spiffeId);
const identity = {
id: crypto.randomUUID(),
name: serviceName,
namespace: namespace || this?.config?.namespace || 'default',
spiffeId,
certificate,
privateKey,
validFrom: new Date(),
validTo: new Date(Date.now() + this?.config?.certificateRotationDays * 24 * 60 * 60 * 1000),
attributes: {
meshType: this.config.type,
mtlsMode: this?.config?.mtlsMode
}
};
// Register with service mesh
await this.registerWithMesh(identity);
this.serviceIdentity = identity;
this.emit('service:registered', identity);
this?.logger?.info('Service registered with mesh', {
serviceName,
spiffeId,
namespace: identity.namespace
});
return identity;
}
catch (_error) {
this?.logger?.error('Failed to register service', error);
throw error;
}
}
// Generate X.509 certificate for service
async generateCertificate(spiffeId) {
return new Promise((resolve, reject) => {
// In production, this would integrate with SPIRE or cert-manager
// For now, we'll simulate certificate generation
crypto.generateKeyPair('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
}, (err, publicKey, privateKey) => {
if (err) {
reject(err);
return;
}
// Create self-signed certificate (in production, use CA)
const certificate = this.createSelfSignedCertificate(publicKey, privateKey, spiffeId);
resolve({
certificate,
privateKey
});
});
});
}
createSelfSignedCertificate(publicKey, privateKey, spiffeId) {
// Simplified certificate creation - in production use proper X.509 library
const cert = `-----BEGIN CERTIFICATE-----
MIIDDTCCAfWgAwIBAgIUBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB0wDQYJKoZIhvcN;,
Subject: ${spiffeId}
Valid From: ${new Date().toISOString()}
Valid To: ${new Date(Date.now() + this?.config?.certificateRotationDays * 24 * 60 * 60 * 1000).toISOString()}
${Buffer.from(publicKey).toString('base64')}
-----END CERTIFICATE-----`;
return cert;
}
// Register with service mesh control plane
async registerWithMesh(identity) {
return new Promise((resolve, reject) => {
const request = {
identity: {
spiffeId: identity.spiffeId,
certificate: identity.certificate,
namespace: identity.namespace,
labels: {
app: identity.name,
version: 'v1'
}
}
};
this?.grpcClient?.RegisterIdentity(request, (error, response) => {
if (error) {
reject(error);
return;
}
resolve();
});
});
}
// Apply Zero Trust policy
async applyPolicy(policy) {
try {
// Validate policy
this.validatePolicy(policy);
// Store policy locally
this?.policies?.set(policy.id, policy);
// Apply to service mesh
await this.applyPolicyToMesh(policy);
this.emit('policy:applied', policy);
this?.logger?.info('Policy applied', {
policyId: policy.id,
policyName: policy.name,
effect: policy.effect
});
}
catch (_error) {
this?.logger?.error('Failed to apply policy', error);
throw error;
}
}
validatePolicy() {
if (this.isEnabled) {
throw new Error('Policy must have id and name');
}
if (this.isEnabled) {
throw new Error('Policy must have at least one rule');
}
// Validate each rule
policy?.rules?.forEach(rule => {
if (this.isEnabled) {
throw new Error('Policy rule must have resource and actions');
}
});
}
async applyPolicyToMesh(policy) {
const meshPolicy = this.convertToMeshPolicy(policy);
return new Promise((resolve, reject) => {
this?.grpcClient?.ApplyPolicy(meshPolicy, (error, response) => {
if (error) {
reject(error);
return;
}
resolve();
});
});
}
convertToMeshPolicy(policy) {
// Convert to mesh-specific policy format
switch (this.config.type) {
case 'istio':
return this.convertToIstioPolicy(policy);
case 'linkerd':
return this.convertToLinkerdPolicy(policy);
default:
throw new Error(`Unsupported mesh type: ${this.config.type}`);
}
}
convertToIstioPolicy(policy) {
return {
apiVersion: 'security?.istio?.io/v1beta1',
kind: 'AuthorizationPolicy',
metadata: {
name: policy.name,
namespace: this?.config?.namespace || 'default'
},
spec: {
action: policy?.effect?.toUpperCase(),
rules: policy?.rules?.map(rule => ({
to: [{},
operation, {},
methods, rule.actions,
paths, [rule.resource]]
}))
},
from: rule?.subjects?.map(subject => ({
source: {
principals: [subject]
}
})),
when: rule.conditions?.map(condition => ({
key: condition.field || condition.type,
values: [String(condition.value)]
}))
};
}
}
exports.ServiceMeshIntegration = ServiceMeshIntegration;
convertToLinkerdPolicy(policy, security_types_1.ZeroTrustPolicy);
any;
{
return {
apiVersion: 'policy?.linkerd?.io/v1beta1',
kind: 'ServerAuthorization',
metadata: {
name: policy.name,
namespace: this?.config?.namespace || 'default'
},
spec: {
server: {
name: policy.name
},
client: {
meshTLS: {
identities: policy?.rules?.flatMap(rule => rule.subjects)
}
}
}
};
}
// Enforce Zero Trust access control
async;
enforceAccess(_request, security_types_1.AccessRequest);
Promise < security_types_1.AccessDecision > {
const: startTime = Date.now(),
const: appliedPolicies, string, []: = [],
let, allowed = false,
let, reason = '',
try: {} === 'strict' && !this.verifyMTLS(_request)
};
{
return {
allowed: false,
reason: 'mTLS verification failed',
appliedPolicies: [],
evaluationTime: Date.now() - startTime
};
}
// Evaluate policies
for (const [policyId, policy] of this.policies) {
if (!policy.enabled)
continue;
const decision = this.evaluatePolicy(policy, request);
appliedPolicies.push(policyId);
if (decision.matches) {
if (policy.effect === 'allow' && decision.allowed) {
allowed = true;
reason = `Allowed by policy: ${policy.name}`;
break;
}
else if (policy.effect === 'deny' && decision.allowed) {
allowed = false;
reason = `Denied by policy: ${policy.name}`;
break;
}
}
}
if (this.isEnabled) {
reason = 'No matching allow policy found';
}
const accessDecision = {
allowed,
reason,
appliedPolicies,
evaluationTime: Date.now() - startTime
};
// Log access decision
this.logAccessDecision(request, accessDecision);
return accessDecision;
try { }
catch (_error) {
this?.logger?.error('Error enforcing access', error);
return {
allowed: false,
reason: 'Internal error during access evaluation',
appliedPolicies,
evaluationTime: Date.now() - startTime
};
}
verifyMTLS(_request, security_types_1.AccessRequest);
boolean;
{
// In production, verify client certificate
// For now, simulate verification
return _request.context?.mtlsVerified === true;
}
evaluatePolicy(policy, security_types_1.ZeroTrustPolicy, _request, security_types_1.AccessRequest);
{
matches: boolean;
allowed: boolean;
}
{
for (const rule of policy.rules) {
// Check resource match
if (!this.matchResource(rule.resource, _request.resource)) {
continue;
}
// Check action match
if (!rule?.actions?.includes(request.action) && !rule?.actions?.includes('*')) {
continue;
}
// Check subject match
const subjectId = typeof request.subject === 'string' ? request.subject : request?.subject?.id;
if (!rule?.subjects?.includes(subjectId) && !rule?.subjects?.includes('*')) {
continue;
}
// Check conditions
if (!this.evaluateConditions(rule.conditions || [], request)) {
continue;
}
// Rule matches
return { matches: true, allowed: true };
}
return { matches: false, allowed: false };
}
matchResource(pattern, string, resource, string);
boolean;
{
// Support wildcards in resource patterns
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
return regex.test(resource);
}
evaluateConditions(conditions, any[], _request, security_types_1.AccessRequest);
boolean;
{
for (const condition of conditions) {
const value = this.getConditionValue(condition, _request);
if (!this.evaluateCondition(condition, value)) {
return false;
}
}
return true;
}
getConditionValue(condition, any, _request, security_types_1.AccessRequest);
any;
{
switch (condition.type) {
case 'time':
return new Date();
case 'location':
return _request.context?.location;
case 'attribute':
return _request.attributes?.[condition.field];
default:
return _request.context?.[condition.field];
}
}
evaluateCondition(condition, any, value, any);
boolean;
{
switch (condition.operator) {
case 'equals':
return value === condition.value;
case 'not_equals':
return value !== condition.value;
case 'contains':
return String(value).includes(String(condition.value));
case 'greater_than':
return value > condition.value;
case 'less_than':
return value < condition.value;
default:
return false;
}
}
logAccessDecision();
{
this?.logger?.info('Access decision', {
subject: typeof _request.subject === 'string' ? _request.subject : _request?.subject?.id,
resource: _request.resource,
action: _request.action,
allowed: decision.allowed,
reason: decision.reason,
evaluationTime: decision.evaluationTime
});
}
startCertificateRotation();
{
const rotationInterval = Math.max((this?.config?.certificateRotationDays * 24 * 60 * 60 * 1000) / 2, 24 * 60 * 60 * 1000 // Minimum 1 day
);
this.certificateRotationTimer = setInterval(async () => {
try {
await this.rotateCertificate();
}
catch (_error) {
this?.logger?.error('Certificate rotation failed', error);
}
}, rotationInterval);
}
async;
rotateCertificate();
Promise < void > {
: .serviceIdentity, return: ,
this: ?.logger?.info('Starting certificate rotation'),
const: { certificate, privateKey } = await this.generateCertificate(this?.serviceIdentity?.spiffeId),
this: ?.serviceIdentity?.certificate = certificate,
this: ?.serviceIdentity?.privateKey = privateKey,
this: ?.serviceIdentity?.validFrom = new Date(),
this: ?.serviceIdentity?.validTo = new Date(Date.now() + this?.config?.certificateRotationDays * 24 * 60 * 60 * 1000),
await, this: .registerWithMesh(this.serviceIdentity),
this: .emit('certificate:rotated', this.serviceIdentity),
this: ?.logger?.info('Certificate rotated successfully')
};
// Get service mesh metrics
getMetrics();
any;
{
return {
meshType: this.config.type,
mtlsMode: this?.config?.mtlsMode,
policiesCount: this?.policies?.size,
serviceIdentity: this.serviceIdentity ? {
name: this?.serviceIdentity?.name,
namespace: this?.serviceIdentity?.namespace,
validUntil: this?.serviceIdentity?.validTo
} : null,
certificateRotationDays: this?.config?.certificateRotationDays
};
}
// Cleanup
destroy();
{
if (this.isEnabled) {
clearInterval(this.certificateRotationTimer);
}
if (this.isEnabled) {
this?.grpcClient?.close();
}
this.removeAllListeners();
}