|
|
|
|
@@ -41,7 +41,7 @@ import (
|
|
|
|
|
"chorus.services/bzzz/pkg/security"
|
|
|
|
|
"chorus.services/bzzz/pkg/ucxl"
|
|
|
|
|
slurpContext "chorus.services/bzzz/pkg/slurp/context"
|
|
|
|
|
"chorus.services/bzzz/pkg/slurp/roles"
|
|
|
|
|
slurpRoles "chorus.services/bzzz/pkg/slurp/roles"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// AccessLevel type alias for backward compatibility
|
|
|
|
|
@@ -276,8 +276,14 @@ func NewRoleCrypto(cfg *config.Config, ageCrypto *AgeCrypto, adminKeyManager *Ad
|
|
|
|
|
// buildAccessControlMatrix constructs the role hierarchy and access control matrix
|
|
|
|
|
func (rc *RoleCrypto) buildAccessControlMatrix() (*AccessControlMatrix, error) {
|
|
|
|
|
matrix := &AccessControlMatrix{
|
|
|
|
|
roleHierarchy: make(map[string][]string),
|
|
|
|
|
accessLevels: make(map[string]AccessLevel),
|
|
|
|
|
roleHierarchy: &RoleHierarchy{
|
|
|
|
|
hierarchy: make(map[string][]string),
|
|
|
|
|
inheritance: make(map[string][]string),
|
|
|
|
|
delegations: make(map[string]*Delegation),
|
|
|
|
|
temporaryRoles: make(map[string]*TemporaryRole),
|
|
|
|
|
roleConstraints: make(map[string]*RoleConstraints),
|
|
|
|
|
},
|
|
|
|
|
accessLevels: make(map[string]security.AccessLevel),
|
|
|
|
|
compartments: make(map[string][]string),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -329,7 +335,7 @@ func (rc *RoleCrypto) buildAccessControlMatrix() (*AccessControlMatrix, error) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for role, accessible := range roleHierarchy {
|
|
|
|
|
matrix.roleHierarchy[role] = accessible
|
|
|
|
|
matrix.roleHierarchy.hierarchy[role] = accessible
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for role, compartments := range roleCompartments {
|
|
|
|
|
@@ -697,7 +703,7 @@ func (rc *RoleCrypto) canAccessContext(role string, encryptedData *EncryptedCont
|
|
|
|
|
rc.accessMatrix.mu.RLock()
|
|
|
|
|
defer rc.accessMatrix.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if accessibleRoles, exists := rc.accessMatrix.roleHierarchy[role]; exists {
|
|
|
|
|
if accessibleRoles, exists := rc.accessMatrix.roleHierarchy.hierarchy[role]; exists {
|
|
|
|
|
for _, accessibleRole := range accessibleRoles {
|
|
|
|
|
if accessibleRole == "*" {
|
|
|
|
|
return true
|
|
|
|
|
@@ -903,14 +909,14 @@ func (rc *RoleCrypto) logAccessEvent(address ucxl.Address, role, accessType stri
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RotateRoleKeys rotates encryption keys for specified roles
|
|
|
|
|
func (rc *RoleCrypto) RotateRoleKeys(roles []string, reason string) (*KeyRotationResult, error) {
|
|
|
|
|
func (rc *RoleCrypto) RotateRoleKeys(roles []string, reason string) (*slurpRoles.KeyRotationResult, error) {
|
|
|
|
|
rc.mu.Lock()
|
|
|
|
|
defer rc.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
result := &KeyRotationResult{
|
|
|
|
|
result := &slurpRoles.KeyRotationResult{
|
|
|
|
|
RotatedRoles: []string{},
|
|
|
|
|
NewKeys: make(map[string]*RoleKey),
|
|
|
|
|
RevokedKeys: make(map[string]*RoleKey),
|
|
|
|
|
NewKeys: make(map[string]*slurpRoles.RoleKey),
|
|
|
|
|
RevokedKeys: make(map[string]*slurpRoles.RoleKey),
|
|
|
|
|
RotatedAt: time.Now(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -929,23 +935,23 @@ func (rc *RoleCrypto) RotateRoleKeys(roles []string, reason string) (*KeyRotatio
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Store old key for revocation
|
|
|
|
|
oldKey := &RoleKey{
|
|
|
|
|
oldKey := &slurpRoles.RoleKey{
|
|
|
|
|
RoleID: role,
|
|
|
|
|
KeyData: []byte(config.EncryptionKeys.PrivateKey),
|
|
|
|
|
KeyType: "age-x25519",
|
|
|
|
|
CreatedAt: config.EncryptionKeys.CreatedAt,
|
|
|
|
|
Version: config.EncryptionKeys.Version,
|
|
|
|
|
Status: KeyStatusRevoked,
|
|
|
|
|
Status: slurpRoles.KeyStatusRevoked,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create new key record
|
|
|
|
|
newKey := &RoleKey{
|
|
|
|
|
newKey := &slurpRoles.RoleKey{
|
|
|
|
|
RoleID: role,
|
|
|
|
|
KeyData: []byte(newKeyPair.PrivateKey),
|
|
|
|
|
KeyType: "age-x25519",
|
|
|
|
|
CreatedAt: newKeyPair.CreatedAt,
|
|
|
|
|
Version: config.EncryptionKeys.Version + 1,
|
|
|
|
|
Status: KeyStatusActive,
|
|
|
|
|
Status: slurpRoles.KeyStatusActive,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update configuration
|
|
|
|
|
@@ -987,19 +993,19 @@ func (rc *RoleCrypto) logKeyRotationEvent(role, reason string, success bool, err
|
|
|
|
|
func (rc *RoleCrypto) ValidateAccess(role string, address ucxl.Address, action string) (*AccessDecision, error) {
|
|
|
|
|
startTime := time.Now()
|
|
|
|
|
|
|
|
|
|
// Create access context
|
|
|
|
|
accessCtx := &AccessContext{
|
|
|
|
|
UserID: rc.config.Agent.ID,
|
|
|
|
|
Role: role,
|
|
|
|
|
Resource: address,
|
|
|
|
|
Action: action,
|
|
|
|
|
AccessLevel: rc.getAccessLevelForRole(role),
|
|
|
|
|
Environment: map[string]interface{}{
|
|
|
|
|
"timestamp": time.Now(),
|
|
|
|
|
"agent_id": rc.config.Agent.ID,
|
|
|
|
|
},
|
|
|
|
|
RequestTime: time.Now(),
|
|
|
|
|
}
|
|
|
|
|
// TODO: Fix AccessContext type
|
|
|
|
|
// accessCtx := &AccessContext{
|
|
|
|
|
// UserID: rc.config.Agent.ID,
|
|
|
|
|
// Role: role,
|
|
|
|
|
// Resource: address,
|
|
|
|
|
// Action: action,
|
|
|
|
|
// AccessLevel: rc.getAccessLevelForRole(role),
|
|
|
|
|
// Environment: map[string]interface{}{
|
|
|
|
|
// "timestamp": time.Now(),
|
|
|
|
|
// "agent_id": rc.config.Agent.ID,
|
|
|
|
|
// },
|
|
|
|
|
// RequestTime: time.Now(),
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Evaluate access using policy engine (simplified for demonstration)
|
|
|
|
|
decision := &AccessDecision{
|
|
|
|
|
@@ -1023,13 +1029,13 @@ func (rc *RoleCrypto) ValidateAccess(role string, address ucxl.Address, action s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetRolePermissions returns the permissions for a specific role
|
|
|
|
|
func (rc *RoleCrypto) GetRolePermissions(role string) (*roles.ContextPermissions, error) {
|
|
|
|
|
func (rc *RoleCrypto) GetRolePermissions(role string) (*slurpRoles.ContextPermissions, error) {
|
|
|
|
|
rc.mu.RLock()
|
|
|
|
|
defer rc.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
accessLevel := rc.getAccessLevelForRole(role)
|
|
|
|
|
|
|
|
|
|
permissions := &roles.ContextPermissions{
|
|
|
|
|
permissions := &slurpRoles.ContextPermissions{
|
|
|
|
|
UserID: rc.config.Agent.ID,
|
|
|
|
|
CanRead: accessLevel >= AccessLow,
|
|
|
|
|
CanWrite: accessLevel >= AccessMedium,
|
|
|
|
|
@@ -1065,7 +1071,7 @@ func (rc *RoleCrypto) GetSecurityMetrics() map[string]interface{} {
|
|
|
|
|
|
|
|
|
|
// Calculate time-based metrics
|
|
|
|
|
now := time.Now()
|
|
|
|
|
todayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
|
|
|
|
// todayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
|
|
|
|
|
|
|
|
|
// Count active and expired keys
|
|
|
|
|
activeKeys := 0
|
|
|
|
|
@@ -1074,18 +1080,16 @@ func (rc *RoleCrypto) GetSecurityMetrics() map[string]interface{} {
|
|
|
|
|
encryptionLayers := 0
|
|
|
|
|
|
|
|
|
|
for _, config := range rc.roleConfigs {
|
|
|
|
|
if config.Keys != nil && len(config.Keys) > 0 {
|
|
|
|
|
activeKeys += len(config.Keys)
|
|
|
|
|
if config.EncryptionKeys != nil {
|
|
|
|
|
activeKeys += 1 // One key pair per role
|
|
|
|
|
encryptionLayers++ // Each role with keys adds an encryption layer
|
|
|
|
|
|
|
|
|
|
// Check for expired keys based on key rotation policy
|
|
|
|
|
if config.KeyRotationPolicy != nil {
|
|
|
|
|
for _, key := range config.Keys {
|
|
|
|
|
keyAge := now.Sub(key.CreatedAt)
|
|
|
|
|
if keyAge > config.KeyRotationPolicy.MaxKeyAge {
|
|
|
|
|
expiredKeys++
|
|
|
|
|
activeKeys--
|
|
|
|
|
}
|
|
|
|
|
keyAge := now.Sub(config.EncryptionKeys.CreatedAt)
|
|
|
|
|
if keyAge > config.KeyRotationPolicy.MaxKeyAge {
|
|
|
|
|
expiredKeys++
|
|
|
|
|
activeKeys--
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Track last key rotation from UpdatedAt
|
|
|
|
|
@@ -1101,46 +1105,47 @@ func (rc *RoleCrypto) GetSecurityMetrics() map[string]interface{} {
|
|
|
|
|
accessViolations := 0
|
|
|
|
|
auditEventsToday := 0
|
|
|
|
|
|
|
|
|
|
// TODO: Fix audit logger QueryEvents method
|
|
|
|
|
if rc.auditLogger != nil {
|
|
|
|
|
// Query for key rotations today
|
|
|
|
|
if auditor, ok := rc.auditLogger.(*AuditLoggerImpl); ok {
|
|
|
|
|
criteria := &AuditQueryCriteria{
|
|
|
|
|
StartTime: &todayStart,
|
|
|
|
|
EndTime: &now,
|
|
|
|
|
EventType: "key_rotation",
|
|
|
|
|
}
|
|
|
|
|
if events, err := auditor.QueryEvents(criteria); err == nil {
|
|
|
|
|
keyRotationsToday = len(events)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Query for access violations today (count both violation types)
|
|
|
|
|
violationCriteria1 := &AuditQueryCriteria{
|
|
|
|
|
StartTime: &todayStart,
|
|
|
|
|
EndTime: &now,
|
|
|
|
|
EventType: "access_violation",
|
|
|
|
|
}
|
|
|
|
|
if events, err := auditor.QueryEvents(violationCriteria1); err == nil {
|
|
|
|
|
accessViolations += len(events)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
violationCriteria2 := &AuditQueryCriteria{
|
|
|
|
|
StartTime: &todayStart,
|
|
|
|
|
EndTime: &now,
|
|
|
|
|
EventType: "unauthorized_access",
|
|
|
|
|
}
|
|
|
|
|
if events, err := auditor.QueryEvents(violationCriteria2); err == nil {
|
|
|
|
|
accessViolations += len(events)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Query for all audit events today
|
|
|
|
|
allEventsCriteria := &AuditQueryCriteria{
|
|
|
|
|
StartTime: &todayStart,
|
|
|
|
|
EndTime: &now,
|
|
|
|
|
}
|
|
|
|
|
if events, err := auditor.QueryEvents(allEventsCriteria); err == nil {
|
|
|
|
|
auditEventsToday = len(events)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// // Query for key rotations today
|
|
|
|
|
// if auditor, ok := rc.auditLogger.(*AuditLoggerImpl); ok {
|
|
|
|
|
// criteria := &AuditQueryCriteria{
|
|
|
|
|
// StartTime: &todayStart,
|
|
|
|
|
// EndTime: &now,
|
|
|
|
|
// EventType: "key_rotation",
|
|
|
|
|
// }
|
|
|
|
|
// if events, err := auditor.QueryEvents(criteria); err == nil {
|
|
|
|
|
// keyRotationsToday = len(events)
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// // Query for access violations today (count both violation types)
|
|
|
|
|
// violationCriteria1 := &AuditQueryCriteria{
|
|
|
|
|
// StartTime: &todayStart,
|
|
|
|
|
// EndTime: &now,
|
|
|
|
|
// EventType: "access_violation",
|
|
|
|
|
// }
|
|
|
|
|
// if events, err := auditor.QueryEvents(violationCriteria1); err == nil {
|
|
|
|
|
// accessViolations += len(events)
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// violationCriteria2 := &AuditQueryCriteria{
|
|
|
|
|
// StartTime: &todayStart,
|
|
|
|
|
// EndTime: &now,
|
|
|
|
|
// EventType: "unauthorized_access",
|
|
|
|
|
// }
|
|
|
|
|
// if events, err := auditor.QueryEvents(violationCriteria2); err == nil {
|
|
|
|
|
// accessViolations += len(events)
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// // Query for all audit events today
|
|
|
|
|
// allEventsCriteria := &AuditQueryCriteria{
|
|
|
|
|
// StartTime: &todayStart,
|
|
|
|
|
// EndTime: &now,
|
|
|
|
|
// }
|
|
|
|
|
// if events, err := auditor.QueryEvents(allEventsCriteria); err == nil {
|
|
|
|
|
// auditEventsToday = len(events)
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculate security score based on various factors
|
|
|
|
|
|