Access Control and Identity Management

Access Control and Identity Management

Cloud storage access control extends beyond traditional file permissions to encompass identity management, API access, and cross-service permissions. Identity and Access Management (IAM) systems in cloud platforms provide fine-grained control over who can access data and what operations they can perform. However, the flexibility of these systems often leads to overly permissive configurations.

Principle of least privilege remains crucial in cloud environments but requires continuous attention as permissions accumulate over time. Regular access reviews identify unnecessary permissions, while automated tools can detect and remediate permission drift. Service accounts and application credentials require particular attention, as they often receive broad permissions for convenience.

// Example: Implementing cloud storage access control with audit
const { Storage } = require('@google-cloud/storage');
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
const winston = require('winston');

class SecureCloudStorageAccess {
    constructor(projectId) {
        this.projectId = projectId;
        this.storage = new Storage({ projectId });
        this.secretManager = new SecretManagerServiceClient();
        this.logger = this.initializeLogger();
        this.accessCache = new Map();
    }
    
    initializeLogger() {
        // Configure structured logging for security events
        return winston.createLogger({
            format: winston.format.json(),
            transports: [
                new winston.transports.Console(),
                new winston.transports.File({ 
                    filename: 'security-audit.log',
                    level: 'info'
                })
            ],
            defaultMeta: { 
                service: 'secure-storage',
                project: this.projectId 
            }
        });
    }
    
    async createSecureBucket(bucketName, classification) {
        const bucket = this.storage.bucket(bucketName);
        
        // Create bucket with security configurations
        await bucket.create({
            location: 'US',
            storageClass: 'STANDARD',
            versioning: { enabled: true },
            encryption: {
                defaultKmsKeyName: await this.getKmsKeyForClassification(classification)
            },
            iamConfiguration: {
                uniformBucketLevelAccess: {
                    enabled: true
                },
                publicAccessPrevention: 'enforced'
            },
            retentionPolicy: {
                retentionPeriod: this.getRetentionPeriod(classification)
            }
        });
        
        // Set bucket IAM policy
        await this.setBucketIamPolicy(bucketName, classification);
        
        // Enable audit logging
        await this.enableAuditLogging(bucketName);
        
        this.logger.info('Secure bucket created', {
            bucketName,
            classification,
            timestamp: new Date().toISOString()
        });
        
        return bucket;
    }
    
    async setBucketIamPolicy(bucketName, classification) {
        const bucket = this.storage.bucket(bucketName);
        
        // Define role mappings based on classification
        const roleMappings = {
            'public': {
                'roles/storage.objectViewer': ['allUsers']
            },
            'internal': {
                'roles/storage.objectViewer': ['domain:company.com'],
                'roles/storage.objectAdmin': ['group:[email protected]']
            },
            'confidential': {
                'roles/storage.objectViewer': ['group:[email protected]'],
                'roles/storage.objectAdmin': ['group:[email protected]']
            },
            'highly_sensitive': {
                'roles/storage.objectViewer': ['group:[email protected]'],
                'roles/storage.objectAdmin': ['user:[email protected]']
            }
        };
        
        const policy = {
            bindings: Object.entries(roleMappings[classification] || {}).map(
                ([role, members]) => ({ role, members })
            ),
            // Add audit logging requirement
            auditConfigs: [{
                service: 'storage.googleapis.com',
                auditLogConfigs: [
                    { logType: 'ADMIN_READ' },
                    { logType: 'DATA_READ' },
                    { logType: 'DATA_WRITE' }
                ]
            }]
        };
        
        await bucket.iam.setPolicy(policy);
    }
    
    async secureFileUpload(bucketName, fileName, fileData, metadata = {}) {
        const bucket = this.storage.bucket(bucketName);
        const file = bucket.file(fileName);
        
        // Generate signed URL for secure upload
        const [signedUrl] = await file.generateSignedPostPolicyV4({
            expires: Date.now() + 15 * 60 * 1000, // 15 minutes
            conditions: [
                ['content-length-range', 0, 50 * 1024 * 1024], // Max 50MB
                ['starts-with', '$Content-Type', 'application/'],
                { 'x-goog-encryption-algorithm': 'AES256' }
            ],
            fields: {
                'x-goog-meta-classification': metadata.classification || 'internal',
                'x-goog-meta-uploaded-by': metadata.userId || 'anonymous',
                'x-goog-meta-upload-timestamp': new Date().toISOString()
            }
        });
        
        // Log upload initiation
        this.logger.info('Secure upload initiated', {
            bucketName,
            fileName,
            userId: metadata.userId,
            classification: metadata.classification,
            clientIp: metadata.clientIp
        });
        
        return signedUrl;
    }
    
    async createTemporaryAccess(bucketName, fileName, userId, duration = 3600) {
        // Implement temporary access with conditions
        const bucket = this.storage.bucket(bucketName);
        const file = bucket.file(fileName);
        
        // Check user authorization
        const authorized = await this.checkUserAuthorization(userId, bucketName, fileName);
        if (!authorized) {
            this.logger.warn('Unauthorized access attempt', {
                userId,
                bucketName,
                fileName,
                timestamp: new Date().toISOString()
            });
            throw new Error('Unauthorized access');
        }
        
        // Generate time-limited signed URL
        const [signedUrl] = await file.getSignedUrl({
            version: 'v4',
            action: 'read',
            expires: Date.now() + duration * 1000,
            extensionHeaders: {
                'x-goog-content-disposition': 'attachment'
            }
        });
        
        // Cache access grant for monitoring
        this.accessCache.set(`${userId}:${fileName}`, {
            grantedAt: new Date(),
            expiresAt: new Date(Date.now() + duration * 1000),
            signedUrl
        });
        
        // Log access grant
        this.logger.info('Temporary access granted', {
            userId,
            fileName,
            duration,
            grantedAt: new Date().toISOString()
        });
        
        return signedUrl;
    }
    
    async revokeAccess(userId, fileName) {
        // Revoke temporary access by removing from cache
        const cacheKey = `${userId}:${fileName}`;
        const accessGrant = this.accessCache.get(cacheKey);
        
        if (accessGrant) {
            this.accessCache.delete(cacheKey);
            
            // Log revocation
            this.logger.info('Access revoked', {
                userId,
                fileName,
                revokedAt: new Date().toISOString(),
                wasValidUntil: accessGrant.expiresAt
            });
        }
        
        // For persistent access, update IAM policies
        await this.removeUserFromFileAcl(userId, fileName);
    }
    
    async monitorSuspiciousAccess() {
        // Implement real-time monitoring for suspicious patterns
        setInterval(async () => {
            const recentLogs = await this.getRecentAccessLogs();
            
            for (const log of recentLogs) {
                // Check for suspicious patterns
                if (this.isSuspiciousAccess(log)) {
                    await this.handleSuspiciousAccess(log);
                }
            }
        }, 60000); // Check every minute
    }
    
    isSuspiciousAccess(log) {
        // Detect various suspicious patterns
        const patterns = [
            // Large number of downloads
            () => log.operation === 'download' && log.count > 100,
            
            // Access from unusual location
            () => log.location && this.isUnusualLocation(log.location),
            
            // Access outside business hours
            () => this.isOutsideBusinessHours(new Date(log.timestamp)),
            
            // Rapid sequential access
            () => log.accessRate > 10 // More than 10 requests per second
        ];
        
        return patterns.some(pattern => pattern());
    }
}