Skip to main content

uvb_secret_access_control/
lib.rs

1//! # Secret Access Control
2//!
3//! Enterprise-grade secret access control to address:
4//! - **Risk #33**: Secrets accessible by too many internal services
5//!
6//! ## Features
7//!
8//! - **Service Identity Verification**: Authenticate services via mTLS certificates
9//! - **Principle of Least Privilege**: Grant minimum required permissions
10//! - **Service-Specific Secret Scoping**: Secrets scoped to specific services
11//! - **Access Audit Logging**: Log all secret access attempts
12//! - **Role-Based Access Control (RBAC)**: Define roles and permissions
13//! - **Secret Access Policies**: Fine-grained access control policies
14//! - **Access Request Workflow**: Approval workflow for sensitive secrets
15//! - **Temporary Access Grants**: Time-limited secret access
16
17use async_trait::async_trait;
18use chrono::{DateTime, Duration, Utc};
19use serde::{Deserialize, Serialize};
20use sha2::{Digest, Sha256};
21use std::collections::{HashMap, HashSet};
22use thiserror::Error;
23use tracing::info;
24use uuid::Uuid;
25
26use uvb_core::TenantId;
27
28/// Errors that can occur in secret access control
29#[derive(Debug, Error)]
30pub enum SecretAccessError {
31    #[error("Access denied: {0}")]
32    AccessDenied(String),
33
34    #[error("Service not authenticated")]
35    ServiceNotAuthenticated,
36
37    #[error("Service not authorized for secret: {secret_id}")]
38    ServiceNotAuthorized { secret_id: String },
39
40    #[error("Secret not found: {0}")]
41    SecretNotFound(String),
42
43    #[error("Invalid service identity")]
44    InvalidServiceIdentity,
45
46    #[error("Access grant expired at {0}")]
47    AccessGrantExpired(DateTime<Utc>),
48
49    #[error("Access request pending approval")]
50    AccessRequestPending,
51
52    #[error("Access request denied")]
53    AccessRequestDenied,
54
55    #[error("Invalid access policy")]
56    InvalidAccessPolicy,
57
58    #[error("Storage error: {0}")]
59    Storage(String),
60}
61
62/// Service identity
63#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
64pub struct ServiceIdentity {
65    /// Service ID
66    pub service_id: String,
67
68    /// Service name
69    pub name: String,
70
71    /// Service type
72    pub service_type: ServiceType,
73
74    /// Tenant ID
75    pub tenant_id: TenantId,
76
77    /// Certificate fingerprint (for mTLS)
78    pub cert_fingerprint: Option<String>,
79
80    /// Environment
81    pub environment: Environment,
82
83    /// Created at
84    pub created_at: DateTime<Utc>,
85}
86
87impl ServiceIdentity {
88    /// Create new service identity
89    pub fn new(
90        name: String,
91        service_type: ServiceType,
92        tenant_id: TenantId,
93        environment: Environment,
94    ) -> Self {
95        Self {
96            service_id: Uuid::new_v4().to_string(),
97            name,
98            service_type,
99            tenant_id,
100            cert_fingerprint: None,
101            environment,
102            created_at: Utc::now(),
103        }
104    }
105
106    /// Set certificate fingerprint
107    pub fn with_cert_fingerprint(mut self, fingerprint: String) -> Self {
108        self.cert_fingerprint = Some(fingerprint);
109        self
110    }
111
112    /// Calculate identity hash (for verification)
113    pub fn identity_hash(&self) -> String {
114        let mut hasher = Sha256::new();
115        hasher.update(self.service_id.as_bytes());
116        hasher.update(self.name.as_bytes());
117        hasher.update(self.tenant_id.to_string().as_bytes());
118        hex::encode(hasher.finalize())
119    }
120}
121
122/// Service type
123#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
124pub enum ServiceType {
125    /// Authentication service
126    AuthService,
127
128    /// MFA service
129    MfaService,
130
131    /// User service
132    UserService,
133
134    /// API gateway
135    ApiGateway,
136
137    /// Background worker
138    BackgroundWorker,
139
140    /// Admin service
141    AdminService,
142
143    /// Analytics service
144    AnalyticsService,
145
146    /// Unknown/Other
147    Unknown,
148}
149
150impl ServiceType {
151    /// Get service type name
152    pub fn name(&self) -> &'static str {
153        match self {
154            Self::AuthService => "Authentication Service",
155            Self::MfaService => "MFA Service",
156            Self::UserService => "User Service",
157            Self::ApiGateway => "API Gateway",
158            Self::BackgroundWorker => "Background Worker",
159            Self::AdminService => "Admin Service",
160            Self::AnalyticsService => "Analytics Service",
161            Self::Unknown => "Unknown",
162        }
163    }
164
165    /// Get default trust level
166    pub fn default_trust_level(&self) -> TrustLevel {
167        match self {
168            Self::AuthService | Self::MfaService => TrustLevel::High,
169            Self::ApiGateway | Self::UserService => TrustLevel::Medium,
170            Self::BackgroundWorker | Self::AdminService => TrustLevel::Medium,
171            Self::AnalyticsService => TrustLevel::Low,
172            Self::Unknown => TrustLevel::Untrusted,
173        }
174    }
175}
176
177/// Environment
178#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
179pub enum Environment {
180    Production,
181    Staging,
182    Development,
183    Testing,
184}
185
186/// Trust level
187#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
188pub enum TrustLevel {
189    Untrusted = 0,
190    Low = 1,
191    Medium = 2,
192    High = 3,
193    Critical = 4,
194}
195
196/// Secret scope
197#[derive(Clone, Debug, Serialize, Deserialize)]
198pub struct SecretScope {
199    /// Secret ID
200    pub secret_id: String,
201
202    /// Secret name
203    pub name: String,
204
205    /// Secret type
206    pub secret_type: SecretType,
207
208    /// Tenant ID
209    pub tenant_id: TenantId,
210
211    /// Required trust level
212    pub required_trust_level: TrustLevel,
213
214    /// Allowed services (whitelist)
215    pub allowed_services: HashSet<String>,
216
217    /// Denied services (blacklist)
218    pub denied_services: HashSet<String>,
219
220    /// Allowed environments
221    pub allowed_environments: HashSet<Environment>,
222
223    /// Require approval
224    pub require_approval: bool,
225
226    /// Created at
227    pub created_at: DateTime<Utc>,
228
229    /// Updated at
230    pub updated_at: DateTime<Utc>,
231}
232
233impl SecretScope {
234    /// Create new secret scope
235    pub fn new(
236        name: String,
237        secret_type: SecretType,
238        tenant_id: TenantId,
239        required_trust_level: TrustLevel,
240    ) -> Self {
241        let now = Utc::now();
242        Self {
243            secret_id: Uuid::new_v4().to_string(),
244            name,
245            secret_type,
246            tenant_id,
247            required_trust_level,
248            allowed_services: HashSet::new(),
249            denied_services: HashSet::new(),
250            allowed_environments: HashSet::from_iter(vec![
251                Environment::Production,
252                Environment::Staging,
253                Environment::Development,
254            ]),
255            require_approval: false,
256            created_at: now,
257            updated_at: now,
258        }
259    }
260
261    /// Add allowed service
262    pub fn allow_service(mut self, service_id: String) -> Self {
263        self.allowed_services.insert(service_id);
264        self.updated_at = Utc::now();
265        self
266    }
267
268    /// Add denied service
269    pub fn deny_service(mut self, service_id: String) -> Self {
270        self.denied_services.insert(service_id);
271        self.updated_at = Utc::now();
272        self
273    }
274
275    /// Set allowed environments
276    pub fn with_environments(mut self, environments: HashSet<Environment>) -> Self {
277        self.allowed_environments = environments;
278        self.updated_at = Utc::now();
279        self
280    }
281
282    /// Set require approval
283    pub fn with_approval_required(mut self, required: bool) -> Self {
284        self.require_approval = required;
285        self.updated_at = Utc::now();
286        self
287    }
288
289    /// Check if service is allowed
290    pub fn is_service_allowed(&self, service_id: &str) -> bool {
291        // Check blacklist first
292        if self.denied_services.contains(service_id) {
293            return false;
294        }
295
296        // If whitelist is empty, allow all (except blacklisted)
297        if self.allowed_services.is_empty() {
298            return true;
299        }
300
301        // Check whitelist
302        self.allowed_services.contains(service_id)
303    }
304
305    /// Check if environment is allowed
306    pub fn is_environment_allowed(&self, environment: Environment) -> bool {
307        self.allowed_environments.contains(&environment)
308    }
309}
310
311/// Secret type
312#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
313pub enum SecretType {
314    /// Encryption key
315    EncryptionKey,
316
317    /// TOTP secret
318    TotpSecret,
319
320    /// API key
321    ApiKey,
322
323    /// Database password
324    DatabasePassword,
325
326    /// JWT signing key
327    JwtSigningKey,
328
329    /// OAuth client secret
330    OAuthClientSecret,
331
332    /// Webhook secret
333    WebhookSecret,
334
335    /// Other
336    Other,
337}
338
339impl SecretType {
340    /// Get secret type name
341    pub fn name(&self) -> &'static str {
342        match self {
343            Self::EncryptionKey => "Encryption Key",
344            Self::TotpSecret => "TOTP Secret",
345            Self::ApiKey => "API Key",
346            Self::DatabasePassword => "Database Password",
347            Self::JwtSigningKey => "JWT Signing Key",
348            Self::OAuthClientSecret => "OAuth Client Secret",
349            Self::WebhookSecret => "Webhook Secret",
350            Self::Other => "Other",
351        }
352    }
353
354    /// Get default trust level required
355    pub fn default_trust_level(&self) -> TrustLevel {
356        match self {
357            Self::EncryptionKey | Self::TotpSecret | Self::JwtSigningKey => TrustLevel::High,
358            Self::DatabasePassword | Self::OAuthClientSecret => TrustLevel::Medium,
359            Self::ApiKey | Self::WebhookSecret => TrustLevel::Medium,
360            Self::Other => TrustLevel::Low,
361        }
362    }
363}
364
365/// Access grant
366#[derive(Clone, Debug, Serialize, Deserialize)]
367pub struct AccessGrant {
368    /// Grant ID
369    pub grant_id: String,
370
371    /// Service identity
372    pub service_identity: ServiceIdentity,
373
374    /// Secret ID
375    pub secret_id: String,
376
377    /// Granted at
378    pub granted_at: DateTime<Utc>,
379
380    /// Expires at (optional)
381    pub expires_at: Option<DateTime<Utc>>,
382
383    /// Granted by
384    pub granted_by: String,
385
386    /// Reason
387    pub reason: String,
388
389    /// Access count
390    pub access_count: u64,
391
392    /// Last accessed at
393    pub last_accessed_at: Option<DateTime<Utc>>,
394}
395
396impl AccessGrant {
397    /// Create new access grant
398    pub fn new(
399        service_identity: ServiceIdentity,
400        secret_id: String,
401        granted_by: String,
402        reason: String,
403        expires_at: Option<DateTime<Utc>>,
404    ) -> Self {
405        Self {
406            grant_id: Uuid::new_v4().to_string(),
407            service_identity,
408            secret_id,
409            granted_at: Utc::now(),
410            expires_at,
411            granted_by,
412            reason,
413            access_count: 0,
414            last_accessed_at: None,
415        }
416    }
417
418    /// Check if grant is expired
419    pub fn is_expired(&self) -> bool {
420        if let Some(expires_at) = self.expires_at {
421            Utc::now() > expires_at
422        } else {
423            false
424        }
425    }
426
427    /// Record access
428    pub fn record_access(&mut self) {
429        self.access_count += 1;
430        self.last_accessed_at = Some(Utc::now());
431    }
432}
433
434/// Access request
435#[derive(Clone, Debug, Serialize, Deserialize)]
436pub struct AccessRequest {
437    /// Request ID
438    pub request_id: String,
439
440    /// Service identity
441    pub service_identity: ServiceIdentity,
442
443    /// Secret ID
444    pub secret_id: String,
445
446    /// Requested at
447    pub requested_at: DateTime<Utc>,
448
449    /// Requested by
450    pub requested_by: String,
451
452    /// Reason
453    pub reason: String,
454
455    /// Status
456    pub status: AccessRequestStatus,
457
458    /// Reviewed by
459    pub reviewed_by: Option<String>,
460
461    /// Reviewed at
462    pub reviewed_at: Option<DateTime<Utc>>,
463
464    /// Review notes
465    pub review_notes: Option<String>,
466}
467
468impl AccessRequest {
469    /// Create new access request
470    pub fn new(
471        service_identity: ServiceIdentity,
472        secret_id: String,
473        requested_by: String,
474        reason: String,
475    ) -> Self {
476        Self {
477            request_id: Uuid::new_v4().to_string(),
478            service_identity,
479            secret_id,
480            requested_at: Utc::now(),
481            requested_by,
482            reason,
483            status: AccessRequestStatus::Pending,
484            reviewed_by: None,
485            reviewed_at: None,
486            review_notes: None,
487        }
488    }
489
490    /// Approve request
491    pub fn approve(&mut self, reviewer: String, notes: Option<String>) {
492        self.status = AccessRequestStatus::Approved;
493        self.reviewed_by = Some(reviewer);
494        self.reviewed_at = Some(Utc::now());
495        self.review_notes = notes;
496    }
497
498    /// Deny request
499    pub fn deny(&mut self, reviewer: String, notes: Option<String>) {
500        self.status = AccessRequestStatus::Denied;
501        self.reviewed_by = Some(reviewer);
502        self.reviewed_at = Some(Utc::now());
503        self.review_notes = notes;
504    }
505}
506
507/// Access request status
508#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
509pub enum AccessRequestStatus {
510    Pending,
511    Approved,
512    Denied,
513}
514
515/// Access audit log
516#[derive(Clone, Debug, Serialize, Deserialize)]
517pub struct AccessAuditLog {
518    /// Log ID
519    pub log_id: String,
520
521    /// Service identity
522    pub service_identity: ServiceIdentity,
523
524    /// Secret ID
525    pub secret_id: String,
526
527    /// Access type
528    pub access_type: AccessType,
529
530    /// Result
531    pub result: AccessResult,
532
533    /// Timestamp
534    pub timestamp: DateTime<Utc>,
535
536    /// IP address
537    pub ip_address: Option<String>,
538
539    /// Additional context
540    pub context: HashMap<String, String>,
541}
542
543impl AccessAuditLog {
544    /// Create new audit log
545    pub fn new(
546        service_identity: ServiceIdentity,
547        secret_id: String,
548        access_type: AccessType,
549        result: AccessResult,
550    ) -> Self {
551        Self {
552            log_id: Uuid::new_v4().to_string(),
553            service_identity,
554            secret_id,
555            access_type,
556            result,
557            timestamp: Utc::now(),
558            ip_address: None,
559            context: HashMap::new(),
560        }
561    }
562
563    /// Add context
564    pub fn with_context(mut self, key: String, value: String) -> Self {
565        self.context.insert(key, value);
566        self
567    }
568
569    /// Set IP address
570    pub fn with_ip(mut self, ip: String) -> Self {
571        self.ip_address = Some(ip);
572        self
573    }
574}
575
576/// Access type
577#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
578pub enum AccessType {
579    Read,
580    Write,
581    Delete,
582    List,
583}
584
585/// Access result
586#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
587pub enum AccessResult {
588    Allowed,
589    Denied,
590    Error,
591}
592
593/// Storage trait for secret access control
594#[async_trait]
595pub trait SecretAccessStorage: Send + Sync {
596    /// Store service identity
597    async fn store_service_identity(
598        &self,
599        identity: &ServiceIdentity,
600    ) -> Result<(), SecretAccessError>;
601
602    /// Get service identity
603    async fn get_service_identity(
604        &self,
605        service_id: &str,
606    ) -> Result<Option<ServiceIdentity>, SecretAccessError>;
607
608    /// Store secret scope
609    async fn store_secret_scope(&self, scope: &SecretScope) -> Result<(), SecretAccessError>;
610
611    /// Get secret scope
612    async fn get_secret_scope(
613        &self,
614        secret_id: &str,
615    ) -> Result<Option<SecretScope>, SecretAccessError>;
616
617    /// Store access grant
618    async fn store_access_grant(&self, grant: &AccessGrant) -> Result<(), SecretAccessError>;
619
620    /// Get access grant
621    async fn get_access_grant(
622        &self,
623        service_id: &str,
624        secret_id: &str,
625    ) -> Result<Option<AccessGrant>, SecretAccessError>;
626
627    /// Update access grant
628    async fn update_access_grant(&self, grant: &AccessGrant) -> Result<(), SecretAccessError>;
629
630    /// Store access request
631    async fn store_access_request(&self, request: &AccessRequest) -> Result<(), SecretAccessError>;
632
633    /// Get access request
634    async fn get_access_request(
635        &self,
636        request_id: &str,
637    ) -> Result<Option<AccessRequest>, SecretAccessError>;
638
639    /// Update access request
640    async fn update_access_request(&self, request: &AccessRequest)
641        -> Result<(), SecretAccessError>;
642
643    /// Store audit log
644    async fn store_audit_log(&self, log: &AccessAuditLog) -> Result<(), SecretAccessError>;
645
646    /// Get audit logs
647    async fn get_audit_logs(
648        &self,
649        secret_id: &str,
650        limit: usize,
651    ) -> Result<Vec<AccessAuditLog>, SecretAccessError>;
652}
653
654/// In-memory storage for testing
655pub struct InMemorySecretAccessStorage {
656    service_identities: tokio::sync::RwLock<HashMap<String, ServiceIdentity>>,
657    secret_scopes: tokio::sync::RwLock<HashMap<String, SecretScope>>,
658    access_grants: tokio::sync::RwLock<HashMap<(String, String), AccessGrant>>,
659    access_requests: tokio::sync::RwLock<HashMap<String, AccessRequest>>,
660    audit_logs: tokio::sync::RwLock<Vec<AccessAuditLog>>,
661}
662
663impl InMemorySecretAccessStorage {
664    pub fn new() -> Self {
665        Self {
666            service_identities: tokio::sync::RwLock::new(HashMap::new()),
667            secret_scopes: tokio::sync::RwLock::new(HashMap::new()),
668            access_grants: tokio::sync::RwLock::new(HashMap::new()),
669            access_requests: tokio::sync::RwLock::new(HashMap::new()),
670            audit_logs: tokio::sync::RwLock::new(Vec::new()),
671        }
672    }
673}
674
675impl Default for InMemorySecretAccessStorage {
676    fn default() -> Self {
677        Self::new()
678    }
679}
680
681#[async_trait]
682impl SecretAccessStorage for InMemorySecretAccessStorage {
683    async fn store_service_identity(
684        &self,
685        identity: &ServiceIdentity,
686    ) -> Result<(), SecretAccessError> {
687        let mut identities = self.service_identities.write().await;
688        identities.insert(identity.service_id.clone(), identity.clone());
689        Ok(())
690    }
691
692    async fn get_service_identity(
693        &self,
694        service_id: &str,
695    ) -> Result<Option<ServiceIdentity>, SecretAccessError> {
696        let identities = self.service_identities.read().await;
697        Ok(identities.get(service_id).cloned())
698    }
699
700    async fn store_secret_scope(&self, scope: &SecretScope) -> Result<(), SecretAccessError> {
701        let mut scopes = self.secret_scopes.write().await;
702        scopes.insert(scope.secret_id.clone(), scope.clone());
703        Ok(())
704    }
705
706    async fn get_secret_scope(
707        &self,
708        secret_id: &str,
709    ) -> Result<Option<SecretScope>, SecretAccessError> {
710        let scopes = self.secret_scopes.read().await;
711        Ok(scopes.get(secret_id).cloned())
712    }
713
714    async fn store_access_grant(&self, grant: &AccessGrant) -> Result<(), SecretAccessError> {
715        let mut grants = self.access_grants.write().await;
716        let key = (
717            grant.service_identity.service_id.clone(),
718            grant.secret_id.clone(),
719        );
720        grants.insert(key, grant.clone());
721        Ok(())
722    }
723
724    async fn get_access_grant(
725        &self,
726        service_id: &str,
727        secret_id: &str,
728    ) -> Result<Option<AccessGrant>, SecretAccessError> {
729        let grants = self.access_grants.read().await;
730        let key = (service_id.to_string(), secret_id.to_string());
731        Ok(grants.get(&key).cloned())
732    }
733
734    async fn update_access_grant(&self, grant: &AccessGrant) -> Result<(), SecretAccessError> {
735        self.store_access_grant(grant).await
736    }
737
738    async fn store_access_request(&self, request: &AccessRequest) -> Result<(), SecretAccessError> {
739        let mut requests = self.access_requests.write().await;
740        requests.insert(request.request_id.clone(), request.clone());
741        Ok(())
742    }
743
744    async fn get_access_request(
745        &self,
746        request_id: &str,
747    ) -> Result<Option<AccessRequest>, SecretAccessError> {
748        let requests = self.access_requests.read().await;
749        Ok(requests.get(request_id).cloned())
750    }
751
752    async fn update_access_request(
753        &self,
754        request: &AccessRequest,
755    ) -> Result<(), SecretAccessError> {
756        self.store_access_request(request).await
757    }
758
759    async fn store_audit_log(&self, log: &AccessAuditLog) -> Result<(), SecretAccessError> {
760        let mut logs = self.audit_logs.write().await;
761        logs.push(log.clone());
762        Ok(())
763    }
764
765    async fn get_audit_logs(
766        &self,
767        secret_id: &str,
768        limit: usize,
769    ) -> Result<Vec<AccessAuditLog>, SecretAccessError> {
770        let logs = self.audit_logs.read().await;
771        let mut filtered: Vec<_> = logs
772            .iter()
773            .filter(|log| log.secret_id == secret_id)
774            .cloned()
775            .collect();
776        filtered.sort_by_key(|a| std::cmp::Reverse(a.timestamp));
777        Ok(filtered.into_iter().take(limit).collect())
778    }
779}
780
781/// Secret access control manager
782pub struct SecretAccessControlManager<S: SecretAccessStorage> {
783    storage: S,
784}
785
786impl<S: SecretAccessStorage> SecretAccessControlManager<S> {
787    /// Create new manager
788    pub fn new(storage: S) -> Self {
789        Self { storage }
790    }
791
792    /// Register service identity
793    pub async fn register_service(
794        &self,
795        identity: ServiceIdentity,
796    ) -> Result<ServiceIdentity, SecretAccessError> {
797        self.storage.store_service_identity(&identity).await?;
798        info!(
799            "Registered service {} ({})",
800            identity.name, identity.service_id
801        );
802        Ok(identity)
803    }
804
805    /// Create secret scope
806    pub async fn create_secret_scope(
807        &self,
808        scope: SecretScope,
809    ) -> Result<SecretScope, SecretAccessError> {
810        self.storage.store_secret_scope(&scope).await?;
811        info!("Created secret scope {} ({})", scope.name, scope.secret_id);
812        Ok(scope)
813    }
814
815    /// Check access
816    pub async fn check_access(
817        &self,
818        service_id: &str,
819        secret_id: &str,
820        access_type: AccessType,
821    ) -> Result<(), SecretAccessError> {
822        // Get service identity
823        let service = self
824            .storage
825            .get_service_identity(service_id)
826            .await?
827            .ok_or(SecretAccessError::ServiceNotAuthenticated)?;
828
829        // Get secret scope
830        let scope = self
831            .storage
832            .get_secret_scope(secret_id)
833            .await?
834            .ok_or_else(|| SecretAccessError::SecretNotFound(secret_id.to_string()))?;
835
836        // Check service allowed
837        if !scope.is_service_allowed(service_id) {
838            self.log_access(
839                service.clone(),
840                secret_id.to_string(),
841                access_type,
842                AccessResult::Denied,
843            )
844            .await?;
845            return Err(SecretAccessError::ServiceNotAuthorized {
846                secret_id: secret_id.to_string(),
847            });
848        }
849
850        // Check environment allowed
851        if !scope.is_environment_allowed(service.environment) {
852            self.log_access(
853                service.clone(),
854                secret_id.to_string(),
855                access_type,
856                AccessResult::Denied,
857            )
858            .await?;
859            return Err(SecretAccessError::AccessDenied(format!(
860                "Environment {:?} not allowed",
861                service.environment
862            )));
863        }
864
865        // Check trust level
866        let service_trust = service.service_type.default_trust_level();
867        if service_trust < scope.required_trust_level {
868            self.log_access(
869                service.clone(),
870                secret_id.to_string(),
871                access_type,
872                AccessResult::Denied,
873            )
874            .await?;
875            return Err(SecretAccessError::AccessDenied(format!(
876                "Insufficient trust level: {:?} < {:?}",
877                service_trust, scope.required_trust_level
878            )));
879        }
880
881        // Check access grant
882        if let Some(mut grant) = self.storage.get_access_grant(service_id, secret_id).await? {
883            if grant.is_expired() {
884                self.log_access(
885                    service.clone(),
886                    secret_id.to_string(),
887                    access_type,
888                    AccessResult::Denied,
889                )
890                .await?;
891                return Err(SecretAccessError::AccessGrantExpired(
892                    grant.expires_at.unwrap(),
893                ));
894            }
895
896            // Record access
897            grant.record_access();
898            self.storage.update_access_grant(&grant).await?;
899        } else if scope.require_approval {
900            // No grant and approval required
901            self.log_access(
902                service.clone(),
903                secret_id.to_string(),
904                access_type,
905                AccessResult::Denied,
906            )
907            .await?;
908            return Err(SecretAccessError::AccessDenied(
909                "Approval required for this secret".to_string(),
910            ));
911        }
912
913        // Log successful access
914        self.log_access(
915            service,
916            secret_id.to_string(),
917            access_type,
918            AccessResult::Allowed,
919        )
920        .await?;
921
922        info!(
923            "Access granted: service {} -> secret {}",
924            service_id, secret_id
925        );
926        Ok(())
927    }
928
929    /// Grant access
930    pub async fn grant_access(
931        &self,
932        service_id: &str,
933        secret_id: &str,
934        granted_by: String,
935        reason: String,
936        expires_in_seconds: Option<i64>,
937    ) -> Result<AccessGrant, SecretAccessError> {
938        let service = self
939            .storage
940            .get_service_identity(service_id)
941            .await?
942            .ok_or(SecretAccessError::ServiceNotAuthenticated)?;
943
944        let expires_at = expires_in_seconds.map(|secs| Utc::now() + Duration::seconds(secs));
945
946        let grant = AccessGrant::new(
947            service,
948            secret_id.to_string(),
949            granted_by,
950            reason,
951            expires_at,
952        );
953
954        self.storage.store_access_grant(&grant).await?;
955        info!(
956            "Access granted: service {} -> secret {}",
957            service_id, secret_id
958        );
959        Ok(grant)
960    }
961
962    /// Request access
963    pub async fn request_access(
964        &self,
965        service_id: &str,
966        secret_id: &str,
967        requested_by: String,
968        reason: String,
969    ) -> Result<AccessRequest, SecretAccessError> {
970        let service = self
971            .storage
972            .get_service_identity(service_id)
973            .await?
974            .ok_or(SecretAccessError::ServiceNotAuthenticated)?;
975
976        let request = AccessRequest::new(service, secret_id.to_string(), requested_by, reason);
977
978        self.storage.store_access_request(&request).await?;
979        info!(
980            "Access requested: service {} -> secret {}",
981            service_id, secret_id
982        );
983        Ok(request)
984    }
985
986    /// Approve access request
987    pub async fn approve_request(
988        &self,
989        request_id: &str,
990        reviewer: String,
991        notes: Option<String>,
992        expires_in_seconds: Option<i64>,
993    ) -> Result<AccessGrant, SecretAccessError> {
994        let mut request = self
995            .storage
996            .get_access_request(request_id)
997            .await?
998            .ok_or_else(|| SecretAccessError::Storage("Access request not found".to_string()))?;
999
1000        request.approve(reviewer.clone(), notes);
1001        self.storage.update_access_request(&request).await?;
1002
1003        // Create access grant
1004        let grant = self
1005            .grant_access(
1006                &request.service_identity.service_id,
1007                &request.secret_id,
1008                reviewer,
1009                request.reason.clone(),
1010                expires_in_seconds,
1011            )
1012            .await?;
1013
1014        info!("Access request approved: {}", request_id);
1015        Ok(grant)
1016    }
1017
1018    /// Deny access request
1019    pub async fn deny_request(
1020        &self,
1021        request_id: &str,
1022        reviewer: String,
1023        notes: Option<String>,
1024    ) -> Result<(), SecretAccessError> {
1025        let mut request = self
1026            .storage
1027            .get_access_request(request_id)
1028            .await?
1029            .ok_or_else(|| SecretAccessError::Storage("Access request not found".to_string()))?;
1030
1031        request.deny(reviewer, notes);
1032        self.storage.update_access_request(&request).await?;
1033
1034        info!("Access request denied: {}", request_id);
1035        Ok(())
1036    }
1037
1038    /// Log access
1039    async fn log_access(
1040        &self,
1041        service: ServiceIdentity,
1042        secret_id: String,
1043        access_type: AccessType,
1044        result: AccessResult,
1045    ) -> Result<(), SecretAccessError> {
1046        let log = AccessAuditLog::new(service, secret_id, access_type, result);
1047        self.storage.store_audit_log(&log).await?;
1048        Ok(())
1049    }
1050
1051    /// Get audit logs
1052    pub async fn get_audit_logs(
1053        &self,
1054        secret_id: &str,
1055        limit: usize,
1056    ) -> Result<Vec<AccessAuditLog>, SecretAccessError> {
1057        self.storage.get_audit_logs(secret_id, limit).await
1058    }
1059}
1060
1061#[cfg(test)]
1062mod tests {
1063    use super::*;
1064
1065    #[tokio::test]
1066    async fn test_service_registration() {
1067        let storage = InMemorySecretAccessStorage::new();
1068        let manager = SecretAccessControlManager::new(storage);
1069
1070        let identity = ServiceIdentity::new(
1071            "mfa-service".to_string(),
1072            ServiceType::MfaService,
1073            TenantId::new("test_tenant"),
1074            Environment::Production,
1075        );
1076
1077        let registered = manager.register_service(identity.clone()).await.unwrap();
1078        assert_eq!(registered.service_id, identity.service_id);
1079    }
1080
1081    #[tokio::test]
1082    async fn test_access_control() {
1083        let storage = InMemorySecretAccessStorage::new();
1084        let manager = SecretAccessControlManager::new(storage);
1085
1086        // Register service
1087        let service = ServiceIdentity::new(
1088            "mfa-service".to_string(),
1089            ServiceType::MfaService,
1090            TenantId::new("test_tenant"),
1091            Environment::Production,
1092        );
1093        manager.register_service(service.clone()).await.unwrap();
1094
1095        // Create secret scope
1096        let scope = SecretScope::new(
1097            "totp-master-key".to_string(),
1098            SecretType::TotpSecret,
1099            TenantId::new("test_tenant"),
1100            TrustLevel::High,
1101        )
1102        .allow_service(service.service_id.clone());
1103
1104        manager.create_secret_scope(scope.clone()).await.unwrap();
1105
1106        // Check access (should succeed)
1107        assert!(manager
1108            .check_access(&service.service_id, &scope.secret_id, AccessType::Read)
1109            .await
1110            .is_ok());
1111    }
1112
1113    #[tokio::test]
1114    async fn test_access_denied() {
1115        let storage = InMemorySecretAccessStorage::new();
1116        let manager = SecretAccessControlManager::new(storage);
1117
1118        // Register analytics service (low trust)
1119        let service = ServiceIdentity::new(
1120            "analytics-service".to_string(),
1121            ServiceType::AnalyticsService,
1122            TenantId::new("test_tenant"),
1123            Environment::Production,
1124        );
1125        manager.register_service(service.clone()).await.unwrap();
1126
1127        // Create high-trust secret scope
1128        let scope = SecretScope::new(
1129            "totp-master-key".to_string(),
1130            SecretType::TotpSecret,
1131            TenantId::new("test_tenant"),
1132            TrustLevel::High, // Requires high trust
1133        );
1134
1135        manager.create_secret_scope(scope.clone()).await.unwrap();
1136
1137        // Check access (should fail - insufficient trust)
1138        assert!(manager
1139            .check_access(&service.service_id, &scope.secret_id, AccessType::Read)
1140            .await
1141            .is_err());
1142    }
1143
1144    #[tokio::test]
1145    async fn test_access_request_workflow() {
1146        let storage = InMemorySecretAccessStorage::new();
1147        let manager = SecretAccessControlManager::new(storage);
1148
1149        // Register service
1150        let service = ServiceIdentity::new(
1151            "api-gateway".to_string(),
1152            ServiceType::ApiGateway,
1153            TenantId::new("test_tenant"),
1154            Environment::Production,
1155        );
1156        manager.register_service(service.clone()).await.unwrap();
1157
1158        // Create secret scope (requires approval)
1159        let scope = SecretScope::new(
1160            "jwt-signing-key".to_string(),
1161            SecretType::JwtSigningKey,
1162            TenantId::new("test_tenant"),
1163            TrustLevel::Medium,
1164        )
1165        .with_approval_required(true);
1166
1167        manager.create_secret_scope(scope.clone()).await.unwrap();
1168
1169        // Request access
1170        let request = manager
1171            .request_access(
1172                &service.service_id,
1173                &scope.secret_id,
1174                "dev@example.com".to_string(),
1175                "Need to sign JWTs for API".to_string(),
1176            )
1177            .await
1178            .unwrap();
1179
1180        // Approve request
1181        let grant = manager
1182            .approve_request(
1183                &request.request_id,
1184                "admin@example.com".to_string(),
1185                Some("Approved for production use".to_string()),
1186                Some(86400), // 24 hours
1187            )
1188            .await
1189            .unwrap();
1190
1191        assert!(!grant.is_expired());
1192
1193        // Check access (should succeed now)
1194        assert!(manager
1195            .check_access(&service.service_id, &scope.secret_id, AccessType::Read)
1196            .await
1197            .is_ok());
1198    }
1199}