fedramp-20x-mcp 0.4.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. fedramp_20x_mcp/__init__.py +14 -0
  2. fedramp_20x_mcp/__main__.py +12 -0
  3. fedramp_20x_mcp/data_loader.py +673 -0
  4. fedramp_20x_mcp/prompts/__init__.py +62 -0
  5. fedramp_20x_mcp/prompts/api_design_guide.txt +432 -0
  6. fedramp_20x_mcp/prompts/ato_package_checklist.txt +75 -0
  7. fedramp_20x_mcp/prompts/audit_preparation.txt +592 -0
  8. fedramp_20x_mcp/prompts/authorization_boundary_review.txt +76 -0
  9. fedramp_20x_mcp/prompts/azure_ksi_automation.txt +997 -0
  10. fedramp_20x_mcp/prompts/continuous_monitoring_setup.txt +61 -0
  11. fedramp_20x_mcp/prompts/documentation_generator.txt +499 -0
  12. fedramp_20x_mcp/prompts/gap_analysis.txt +25 -0
  13. fedramp_20x_mcp/prompts/initial_assessment_roadmap.txt +202 -0
  14. fedramp_20x_mcp/prompts/ksi_implementation_priorities.txt +283 -0
  15. fedramp_20x_mcp/prompts/migration_from_rev5.txt +440 -0
  16. fedramp_20x_mcp/prompts/quarterly_review_checklist.txt +231 -0
  17. fedramp_20x_mcp/prompts/significant_change_assessment.txt +50 -0
  18. fedramp_20x_mcp/prompts/vendor_evaluation.txt +349 -0
  19. fedramp_20x_mcp/prompts/vulnerability_remediation_timeline.txt +45 -0
  20. fedramp_20x_mcp/server.py +270 -0
  21. fedramp_20x_mcp/templates/__init__.py +75 -0
  22. fedramp_20x_mcp/templates/bicep/afr.txt +33 -0
  23. fedramp_20x_mcp/templates/bicep/cna.txt +48 -0
  24. fedramp_20x_mcp/templates/bicep/generic.txt +47 -0
  25. fedramp_20x_mcp/templates/bicep/iam.txt +211 -0
  26. fedramp_20x_mcp/templates/bicep/mla.txt +82 -0
  27. fedramp_20x_mcp/templates/bicep/rpl.txt +44 -0
  28. fedramp_20x_mcp/templates/bicep/svc.txt +54 -0
  29. fedramp_20x_mcp/templates/code/generic_csharp.txt +65 -0
  30. fedramp_20x_mcp/templates/code/generic_powershell.txt +65 -0
  31. fedramp_20x_mcp/templates/code/generic_python.txt +63 -0
  32. fedramp_20x_mcp/templates/code/iam_csharp.txt +150 -0
  33. fedramp_20x_mcp/templates/code/iam_powershell.txt +162 -0
  34. fedramp_20x_mcp/templates/code/iam_python.txt +224 -0
  35. fedramp_20x_mcp/templates/code/mla_python.txt +124 -0
  36. fedramp_20x_mcp/templates/terraform/afr.txt +29 -0
  37. fedramp_20x_mcp/templates/terraform/cna.txt +50 -0
  38. fedramp_20x_mcp/templates/terraform/generic.txt +40 -0
  39. fedramp_20x_mcp/templates/terraform/iam.txt +219 -0
  40. fedramp_20x_mcp/templates/terraform/mla.txt +29 -0
  41. fedramp_20x_mcp/templates/terraform/rpl.txt +32 -0
  42. fedramp_20x_mcp/templates/terraform/svc.txt +46 -0
  43. fedramp_20x_mcp/tools/__init__.py +167 -0
  44. fedramp_20x_mcp/tools/definitions.py +154 -0
  45. fedramp_20x_mcp/tools/documentation.py +155 -0
  46. fedramp_20x_mcp/tools/enhancements.py +2256 -0
  47. fedramp_20x_mcp/tools/evidence.py +701 -0
  48. fedramp_20x_mcp/tools/export.py +753 -0
  49. fedramp_20x_mcp/tools/ksi.py +90 -0
  50. fedramp_20x_mcp/tools/requirements.py +163 -0
  51. fedramp_20x_mcp-0.4.8.dist-info/METADATA +877 -0
  52. fedramp_20x_mcp-0.4.8.dist-info/RECORD +55 -0
  53. fedramp_20x_mcp-0.4.8.dist-info/WHEEL +4 -0
  54. fedramp_20x_mcp-0.4.8.dist-info/entry_points.txt +2 -0
  55. fedramp_20x_mcp-0.4.8.dist-info/licenses/LICENSE +27 -0
@@ -0,0 +1,65 @@
1
+ ## PowerShell Code
2
+
3
+ ```powershell
4
+ #Requires -Modules Az.Accounts, Az.Storage
5
+
6
+ <#
7
+ .SYNOPSIS
8
+ Generic KSI evidence collector for FedRAMP 20x
9
+ #>
10
+
11
+ param(
12
+ [Parameter(Mandatory=$true)]
13
+ [string]$KsiId,
14
+
15
+ [Parameter(Mandatory=$false)]
16
+ [string]$StorageAccountName = $env:EVIDENCE_STORAGE_ACCOUNT
17
+ )
18
+
19
+ function Get-KSIEvidence {
20
+ param([string]$KsiId)
21
+
22
+ $evidence = @{
23
+ collection_date = (Get-Date).ToUniversalTime().ToString("o")
24
+ ksi_id = $KsiId
25
+ compliance_status = "compliant"
26
+ evidence_data = @{
27
+ # Add your evidence data here
28
+ }
29
+ }
30
+
31
+ return $evidence
32
+ }
33
+
34
+ function Save-Evidence {
35
+ param(
36
+ [hashtable]$Evidence,
37
+ [string]$StorageAccount
38
+ )
39
+
40
+ $context = New-AzStorageContext -StorageAccountName $StorageAccount -UseConnectedAccount
41
+
42
+ $timestamp = Get-Date -Format "yyyy-MM-dd"
43
+ $blobName = "evidence/$timestamp.json"
44
+
45
+ $json = $Evidence | ConvertTo-Json -Depth 10
46
+ $tempFile = [System.IO.Path]::GetTempFileName()
47
+ $json | Out-File -FilePath $tempFile -Encoding UTF8
48
+
49
+ Set-AzStorageBlobContent `
50
+ -File $tempFile `
51
+ -Container "evidence" `
52
+ -Blob $blobName `
53
+ -Context $context `
54
+ -Force
55
+
56
+ Remove-Item $tempFile
57
+ Write-Host "✓ Evidence stored: $blobName"
58
+ }
59
+
60
+ # Main
61
+ $evidence = Get-KSIEvidence -KsiId $KsiId
62
+ Save-Evidence -Evidence $evidence -StorageAccount $StorageAccountName
63
+
64
+ Write-Host "Status: $($evidence.compliance_status)"
65
+ ```
@@ -0,0 +1,63 @@
1
+ ## Python Code
2
+
3
+ ```python
4
+ #!/usr/bin/env python3
5
+ \"\"\"
6
+ Generic KSI Evidence Collector
7
+ Collects compliance evidence and stores in Azure Blob Storage
8
+ \"\"\"
9
+
10
+ import os
11
+ import json
12
+ from datetime import datetime
13
+ from azure.identity import DefaultAzureCredential
14
+ from azure.storage.blob import BlobServiceClient
15
+
16
+ def collect_evidence():
17
+ \"\"\"Collect evidence for the KSI\"\"\"
18
+ # Customize this function based on your KSI requirements
19
+ evidence = {
20
+ "collection_date": datetime.utcnow().isoformat(),
21
+ "ksi_id": "KSI-XXX-XX",
22
+ "compliance_status": "compliant",
23
+ "evidence_data": {
24
+ # Add your evidence data here
25
+ }
26
+ }
27
+ return evidence
28
+
29
+ def store_evidence(evidence_data: dict):
30
+ \"\"\"Store evidence in Azure Blob Storage\"\"\"
31
+ credential = DefaultAzureCredential()
32
+ storage_account = os.environ["EVIDENCE_STORAGE_ACCOUNT"]
33
+
34
+ blob_service_client = BlobServiceClient(
35
+ account_url=f"https://{storage_account}.blob.core.windows.net",
36
+ credential=credential
37
+ )
38
+
39
+ timestamp = datetime.utcnow().strftime("%Y-%m-%d")
40
+ blob_name = f"evidence/{timestamp}.json"
41
+
42
+ blob_client = blob_service_client.get_blob_client(
43
+ container="evidence",
44
+ blob=blob_name
45
+ )
46
+
47
+ evidence_json = json.dumps(evidence_data, indent=2)
48
+ blob_client.upload_blob(evidence_json, overwrite=True)
49
+
50
+ return blob_name
51
+
52
+ def main():
53
+ print(f"Starting evidence collection: {datetime.utcnow()}")
54
+
55
+ evidence = collect_evidence()
56
+ blob_name = store_evidence(evidence)
57
+
58
+ print(f"✓ Evidence stored: {blob_name}")
59
+ print(f"Status: {evidence['compliance_status']}")
60
+
61
+ if __name__ == "__main__":
62
+ main()
63
+ ```
@@ -0,0 +1,150 @@
1
+ ## C# Code (.NET 8)
2
+
3
+ ```csharp
4
+ using Azure.Identity;
5
+ using Azure.Storage.Blobs;
6
+ using Microsoft.Graph;
7
+ using System.Text.Json;
8
+
9
+ public class IAMEvidenceCollector
10
+ {
11
+ private readonly GraphServiceClient _graphClient;
12
+ private readonly BlobServiceClient _blobClient;
13
+ private readonly string _evidenceContainer = "iam-evidence";
14
+
15
+ public IAMEvidenceCollector()
16
+ {
17
+ var credential = new DefaultAzureCredential();
18
+ _graphClient = new GraphServiceClient(credential);
19
+
20
+ var storageAccount = Environment.GetEnvironmentVariable("EVIDENCE_STORAGE_ACCOUNT");
21
+ _blobClient = new BlobServiceClient(
22
+ new Uri($"https://{storageAccount}.blob.core.windows.net"),
23
+ credential
24
+ );
25
+ }
26
+
27
+ public async Task<MFAEvidence> CollectMFAEvidenceAsync()
28
+ {
29
+ var evidence = new MFAEvidence
30
+ {
31
+ CollectionDate = DateTime.UtcNow,
32
+ KsiId = "KSI-IAM-01"
33
+ };
34
+
35
+ // Get all users
36
+ var users = await _graphClient.Users.GetAsync();
37
+
38
+ foreach (var user in users.Value)
39
+ {
40
+ evidence.TotalUsers++;
41
+
42
+ // Get authentication methods
43
+ var authMethods = await _graphClient.Users[user.Id]
44
+ .Authentication.Methods.GetAsync();
45
+
46
+ bool hasPhishingResistant = authMethods.Value
47
+ .Any(m => m.OdataType.Contains("fido2", StringComparison.OrdinalIgnoreCase));
48
+
49
+ if (hasPhishingResistant)
50
+ {
51
+ evidence.UsersWithMFA++;
52
+ }
53
+ else
54
+ {
55
+ evidence.NonCompliantUsers.Add(new UserInfo
56
+ {
57
+ UserId = user.Id,
58
+ UserPrincipalName = user.UserPrincipalName
59
+ });
60
+ }
61
+ }
62
+
63
+ evidence.CompliancePercentage = evidence.TotalUsers > 0
64
+ ? (double)evidence.UsersWithMFA / evidence.TotalUsers * 100
65
+ : 0;
66
+
67
+ return evidence;
68
+ }
69
+
70
+ public async Task StoreEvidenceAsync<T>(T evidence, string evidenceType)
71
+ {
72
+ var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd");
73
+ var blobName = $"{evidenceType}/{timestamp}.json";
74
+
75
+ var containerClient = _blobClient.GetBlobContainerClient(_evidenceContainer);
76
+ await containerClient.CreateIfNotExistsAsync();
77
+
78
+ var blobClient = containerClient.GetBlobClient(blobName);
79
+ var json = JsonSerializer.Serialize(evidence, new JsonSerializerOptions
80
+ {
81
+ WriteIndented = true
82
+ });
83
+
84
+ await blobClient.UploadAsync(
85
+ BinaryData.FromString(json),
86
+ overwrite: true
87
+ );
88
+
89
+ Console.WriteLine($"✓ Evidence stored: {blobName}");
90
+ }
91
+
92
+ public async Task RunCollectionAsync()
93
+ {
94
+ Console.WriteLine($"Starting IAM evidence collection: {DateTime.UtcNow}");
95
+
96
+ var mfaEvidence = await CollectMFAEvidenceAsync();
97
+ await StoreEvidenceAsync(mfaEvidence, "ksi-iam-01-mfa");
98
+
99
+ Console.WriteLine($"MFA Compliance: {mfaEvidence.CompliancePercentage:F1}%");
100
+ Console.WriteLine("✓ IAM evidence collection complete");
101
+ }
102
+ }
103
+
104
+ public class MFAEvidence
105
+ {
106
+ public DateTime CollectionDate { get; set; }
107
+ public string KsiId { get; set; }
108
+ public int TotalUsers { get; set; }
109
+ public int UsersWithMFA { get; set; }
110
+ public double CompliancePercentage { get; set; }
111
+ public List<UserInfo> NonCompliantUsers { get; set; } = new();
112
+ }
113
+
114
+ public class UserInfo
115
+ {
116
+ public string UserId { get; set; }
117
+ public string UserPrincipalName { get; set; }
118
+ }
119
+
120
+ // Azure Function entry point
121
+ public static class IAMEvidenceFunction
122
+ {
123
+ [FunctionName("CollectIAMEvidence")]
124
+ public static async Task Run(
125
+ [TimerTrigger("0 0 2 * * *")] TimerInfo timer, // Daily at 2 AM
126
+ ILogger log)
127
+ {
128
+ log.LogInformation("IAM evidence collection triggered");
129
+
130
+ var collector = new IAMEvidenceCollector();
131
+ await collector.RunCollectionAsync();
132
+ }
133
+ }
134
+ ```
135
+
136
+ ### Project File (csproj)
137
+ ```xml
138
+ <Project Sdk="Microsoft.NET.Sdk">
139
+ <PropertyGroup>
140
+ <TargetFramework>net8.0</TargetFramework>
141
+ <AzureFunctionsVersion>v4</AzureFunctionsVersion>
142
+ </PropertyGroup>
143
+ <ItemGroup>
144
+ <PackageReference Include="Azure.Identity" Version="1.10.4" />
145
+ <PackageReference Include="Azure.Storage.Blobs" Version="12.19.1" />
146
+ <PackageReference Include="Microsoft.Graph" Version="5.36.0" />
147
+ <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.20.0" />
148
+ </ItemGroup>
149
+ </Project>
150
+ ```
@@ -0,0 +1,162 @@
1
+ ## PowerShell Code
2
+
3
+ ```powershell
4
+ #Requires -Modules Az.Accounts, Az.Storage, Microsoft.Graph
5
+
6
+ <#
7
+ .SYNOPSIS
8
+ Collects IAM evidence for FedRAMP 20x KSI-IAM-01
9
+ .DESCRIPTION
10
+ Gathers MFA enrollment and usage data from Microsoft Entra ID
11
+ and stores evidence in Azure Blob Storage
12
+ #>
13
+
14
+ [CmdletBinding()]
15
+ param(
16
+ [Parameter(Mandatory=$false)]
17
+ [string]$StorageAccountName = $env:EVIDENCE_STORAGE_ACCOUNT,
18
+
19
+ [Parameter(Mandatory=$false)]
20
+ [string]$ContainerName = "iam-evidence"
21
+ )
22
+
23
+ # Connect to Microsoft Graph
24
+ Connect-MgGraph -Scopes "User.Read.All", "UserAuthenticationMethod.Read.All"
25
+
26
+ function Get-MFAEvidence {
27
+ Write-Host "Collecting MFA evidence..." -ForegroundColor Cyan
28
+
29
+ $evidence = @{
30
+ collection_date = (Get-Date).ToUniversalTime().ToString("o")
31
+ ksi_id = "KSI-IAM-01"
32
+ total_users = 0
33
+ users_with_mfa = 0
34
+ non_compliant_users = @()
35
+ mfa_methods = @{}
36
+ }
37
+
38
+ # Get all users
39
+ $users = Get-MgUser -All
40
+
41
+ foreach ($user in $users) {
42
+ $evidence.total_users++
43
+
44
+ # Get authentication methods
45
+ $authMethods = Get-MgUserAuthenticationMethod -UserId $user.Id
46
+
47
+ $hasPhishingResistant = $false
48
+ $userMethods = @()
49
+
50
+ foreach ($method in $authMethods) {
51
+ $methodType = $method.AdditionalProperties.'@odata.type'
52
+ $userMethods += $methodType
53
+
54
+ # Check for FIDO2
55
+ if ($methodType -like "*fido2*") {
56
+ $hasPhishingResistant = $true
57
+ }
58
+ }
59
+
60
+ if ($hasPhishingResistant) {
61
+ $evidence.users_with_mfa++
62
+ }
63
+ else {
64
+ $evidence.non_compliant_users += @{
65
+ user_id = $user.Id
66
+ upn = $user.UserPrincipalName
67
+ methods = $userMethods
68
+ }
69
+ }
70
+
71
+ # Count method types
72
+ foreach ($method in $userMethods) {
73
+ if ($evidence.mfa_methods.ContainsKey($method)) {
74
+ $evidence.mfa_methods[$method]++
75
+ }
76
+ else {
77
+ $evidence.mfa_methods[$method] = 1
78
+ }
79
+ }
80
+ }
81
+
82
+ # Calculate compliance
83
+ if ($evidence.total_users -gt 0) {
84
+ $evidence.compliance_percentage = [math]::Round(
85
+ ($evidence.users_with_mfa / $evidence.total_users) * 100, 2
86
+ )
87
+ }
88
+ else {
89
+ $evidence.compliance_percentage = 0
90
+ }
91
+
92
+ return $evidence
93
+ }
94
+
95
+ function Save-Evidence {
96
+ param(
97
+ [Parameter(Mandatory=$true)]
98
+ [hashtable]$Evidence,
99
+
100
+ [Parameter(Mandatory=$true)]
101
+ [string]$EvidenceType
102
+ )
103
+
104
+ Write-Host "Storing evidence..." -ForegroundColor Cyan
105
+
106
+ # Connect to Azure Storage
107
+ $storageContext = New-AzStorageContext -StorageAccountName $StorageAccountName -UseConnectedAccount
108
+
109
+ # Create container if it doesn't exist
110
+ $container = Get-AzStorageContainer -Name $ContainerName -Context $storageContext -ErrorAction SilentlyContinue
111
+ if (-not $container) {
112
+ New-AzStorageContainer -Name $ContainerName -Context $storageContext -Permission Off
113
+ }
114
+
115
+ # Create blob name with timestamp
116
+ $timestamp = Get-Date -Format "yyyy-MM-dd"
117
+ $blobName = "$EvidenceType/$timestamp.json"
118
+
119
+ # Convert to JSON and upload
120
+ $json = $Evidence | ConvertTo-Json -Depth 10
121
+ $tempFile = [System.IO.Path]::GetTempFileName()
122
+ $json | Out-File -FilePath $tempFile -Encoding UTF8
123
+
124
+ Set-AzStorageBlobContent `
125
+ -File $tempFile `
126
+ -Container $ContainerName `
127
+ -Blob $blobName `
128
+ -Context $storageContext `
129
+ -Force
130
+
131
+ Remove-Item $tempFile
132
+
133
+ Write-Host "✓ Evidence stored: $blobName" -ForegroundColor Green
134
+ }
135
+
136
+ # Main execution
137
+ try {
138
+ Write-Host "Starting IAM evidence collection: $(Get-Date)" -ForegroundColor Yellow
139
+
140
+ # Collect MFA evidence
141
+ $mfaEvidence = Get-MFAEvidence
142
+ Save-Evidence -Evidence $mfaEvidence -EvidenceType "ksi-iam-01-mfa"
143
+
144
+ Write-Host "MFA Compliance: $($mfaEvidence.compliance_percentage)%" -ForegroundColor Green
145
+ Write-Host "✓ IAM evidence collection complete" -ForegroundColor Green
146
+ }
147
+ catch {
148
+ Write-Error "Evidence collection failed: $_"
149
+ exit 1
150
+ }
151
+ finally {
152
+ Disconnect-MgGraph
153
+ }
154
+ ```
155
+
156
+ ### Azure Automation Runbook
157
+ To deploy this as an Azure Automation Runbook:
158
+
159
+ 1. Create the runbook in Azure Automation
160
+ 2. Add required modules: Az.Accounts, Az.Storage, Microsoft.Graph
161
+ 3. Configure Managed Identity with appropriate permissions
162
+ 4. Schedule for daily execution
@@ -0,0 +1,224 @@
1
+ ## Python Code
2
+
3
+ ```python
4
+ #!/usr/bin/env python3
5
+ \"\"\"
6
+ IAM Evidence Collector for FedRAMP 20x
7
+ Collects MFA usage, authentication logs, and access control evidence
8
+ \"\"\"
9
+
10
+ import os
11
+ import json
12
+ from datetime import datetime, timedelta
13
+ from azure.identity import DefaultAzureCredential
14
+ from azure.mgmt.resource import ResourceManagementClient
15
+ from azure.storage.blob import BlobServiceClient
16
+ from msgraph import GraphServiceClient
17
+
18
+ # Configuration
19
+ SUBSCRIPTION_ID = os.environ["AZURE_SUBSCRIPTION_ID"]
20
+ STORAGE_ACCOUNT = os.environ["EVIDENCE_STORAGE_ACCOUNT"]
21
+ EVIDENCE_CONTAINER = "iam-evidence"
22
+
23
+ async def collect_mfa_evidence():
24
+ \"\"\"Collect MFA enrollment and usage evidence for KSI-IAM-01\"\"\"
25
+ # WAF Security: Use managed identity with explicit configuration
26
+ credential = DefaultAzureCredential(
27
+ exclude_environment_credential=False,
28
+ exclude_managed_identity_credential=False,
29
+ exclude_shared_token_cache_credential=True,
30
+ logging_enable=True # Enable for troubleshooting
31
+ )
32
+ graph_client = GraphServiceClient(credential)
33
+
34
+ # Get all users
35
+ users = await graph_client.users.get()
36
+
37
+ mfa_report = {
38
+ "collection_date": datetime.utcnow().isoformat(),
39
+ "ksi_id": "KSI-IAM-01",
40
+ "total_users": 0,
41
+ "users_with_mfa": 0,
42
+ "mfa_methods": {},
43
+ "non_compliant_users": []
44
+ }
45
+
46
+ for user in users.value:
47
+ mfa_report["total_users"] += 1
48
+
49
+ # Get authentication methods
50
+ auth_methods = await graph_client.users.by_user_id(user.id).authentication.methods.get()
51
+
52
+ has_phishing_resistant = False
53
+ user_methods = []
54
+
55
+ for method in auth_methods.value:
56
+ method_type = method.odata_type
57
+ user_methods.append(method_type)
58
+
59
+ # Check for FIDO2 (phishing-resistant)
60
+ if "fido2" in method_type.lower():
61
+ has_phishing_resistant = True
62
+
63
+ if has_phishing_resistant:
64
+ mfa_report["users_with_mfa"] += 1
65
+ else:
66
+ mfa_report["non_compliant_users"].append({
67
+ "user_id": user.id,
68
+ "upn": user.user_principal_name,
69
+ "methods": user_methods
70
+ })
71
+
72
+ # Count method types
73
+ for method in user_methods:
74
+ mfa_report["mfa_methods"][method] = mfa_report["mfa_methods"].get(method, 0) + 1
75
+
76
+ # Calculate compliance percentage
77
+ mfa_report["compliance_percentage"] = (
78
+ mfa_report["users_with_mfa"] / mfa_report["total_users"] * 100
79
+ if mfa_report["total_users"] > 0 else 0
80
+ )
81
+
82
+ return mfa_report
83
+
84
+ async def collect_conditional_access_evidence():
85
+ \"\"\"Collect Conditional Access policy evidence for KSI-IAM-05\"\"\"
86
+ credential = DefaultAzureCredential(
87
+ exclude_environment_credential=False,
88
+ exclude_managed_identity_credential=False,
89
+ exclude_shared_token_cache_credential=True
90
+ )
91
+ graph_client = GraphServiceClient(credential)
92
+
93
+ # Get all CA policies
94
+ policies = await graph_client.identity.conditional_access.policies.get()
95
+
96
+ ca_report = {
97
+ "collection_date": datetime.utcnow().isoformat(),
98
+ "ksi_id": "KSI-IAM-05",
99
+ "total_policies": len(policies.value),
100
+ "enabled_policies": 0,
101
+ "policies": []
102
+ }
103
+
104
+ for policy in policies.value:
105
+ policy_info = {
106
+ "id": policy.id,
107
+ "display_name": policy.display_name,
108
+ "state": policy.state,
109
+ "conditions": str(policy.conditions),
110
+ "grant_controls": str(policy.grant_controls)
111
+ }
112
+
113
+ if policy.state == "enabled":
114
+ ca_report["enabled_policies"] += 1
115
+
116
+ ca_report["policies"].append(policy_info)
117
+
118
+ return ca_report
119
+
120
+ async def store_evidence(evidence_data: dict, evidence_type: str):
121
+ \"\"\"Store evidence in Azure Blob Storage with immutability and metadata\"\"\"
122
+ # WAF Security: Use managed identity for authentication
123
+ credential = DefaultAzureCredential(
124
+ exclude_environment_credential=False, # Allow environment variables in dev
125
+ exclude_managed_identity_credential=False, # Use managed identity in Azure
126
+ exclude_shared_token_cache_credential=True, # Don't use cached tokens
127
+ logging_enable=True # Enable SDK logging for troubleshooting
128
+ )
129
+
130
+ blob_service_client = BlobServiceClient(
131
+ account_url=f"https://{STORAGE_ACCOUNT}.blob.core.windows.net",
132
+ credential=credential,
133
+ connection_timeout=30, # WAF Reliability: Set timeout
134
+ read_timeout=30
135
+ )
136
+
137
+ # Create blob name with timestamp
138
+ timestamp = datetime.utcnow().strftime("%Y-%m-%d-%H%M%S")
139
+ blob_name = f"{evidence_type}/{timestamp}.json"
140
+
141
+ try:
142
+ # Get blob client
143
+ blob_client = blob_service_client.get_blob_client(
144
+ container=EVIDENCE_CONTAINER,
145
+ blob=blob_name
146
+ )
147
+
148
+ evidence_json = json.dumps(evidence_data, indent=2)
149
+
150
+ # WAF Security: Add metadata for evidence chain of custody
151
+ metadata = {
152
+ "ksi_id": evidence_data.get("ksi_id", "unknown"),
153
+ "collection_date": evidence_data.get("collection_date", ""),
154
+ "evidence_type": evidence_type,
155
+ "version": "1.0"
156
+ }
157
+
158
+ # Upload evidence with metadata
159
+ blob_client.upload_blob(
160
+ evidence_json,
161
+ overwrite=False, # Prevent accidental overwrites
162
+ metadata=metadata,
163
+ tags={"compliance": "fedramp", "type": evidence_type}
164
+ )
165
+
166
+ # WAF Operational Excellence: Log successful upload
167
+ print(f"✓ Evidence stored: {blob_name}")
168
+ print(f" Size: {len(evidence_json)} bytes")
169
+ return blob_name
170
+
171
+ except Exception as e:
172
+ # WAF Reliability: Proper error handling
173
+ print(f"✗ Failed to store evidence: {str(e)}")
174
+ raise
175
+
176
+ async def main():
177
+ \"\"\"Main evidence collection function\"\"\"
178
+ print(f"Starting IAM evidence collection: {datetime.utcnow()}")
179
+
180
+ # Collect MFA evidence
181
+ mfa_evidence = await collect_mfa_evidence()
182
+ await store_evidence(mfa_evidence, "ksi-iam-01-mfa")
183
+ print(f"MFA Compliance: {mfa_evidence['compliance_percentage']:.1f}%")
184
+
185
+ # Collect Conditional Access evidence
186
+ ca_evidence = await collect_conditional_access_evidence()
187
+ await store_evidence(ca_evidence, "ksi-iam-05-conditional-access")
188
+ print(f"CA Policies: {ca_evidence['enabled_policies']}/{ca_evidence['total_policies']} enabled")
189
+
190
+ print("✓ IAM evidence collection complete")
191
+
192
+ if __name__ == "__main__":
193
+ import asyncio
194
+ asyncio.run(main())
195
+ ```
196
+
197
+ ### Requirements (requirements.txt)
198
+ ```
199
+ # Azure SDK for Python - Use latest stable versions
200
+ azure-identity>=1.18.0 # Latest stable as of Dec 2025
201
+ azure-mgmt-resource>=23.1.0
202
+ azure-storage-blob>=12.23.0
203
+ msgraph-sdk>=1.10.0
204
+ azure-monitor-query>=1.5.0
205
+
206
+ # Optional: Retry and resilience
207
+ tenacity>=8.2.0 # For custom retry logic
208
+ ```
209
+
210
+ ### Environment Variables
211
+ ```bash
212
+ # Required for local development and Azure deployment
213
+ export AZURE_SUBSCRIPTION_ID="your-subscription-id"
214
+ export EVIDENCE_STORAGE_ACCOUNT="stfedrampprodevidence"
215
+ export AZURE_TENANT_ID="your-tenant-id"
216
+
217
+ # Optional: For local development only
218
+ export AZURE_CLIENT_ID="your-app-registration-client-id"
219
+ export AZURE_CLIENT_SECRET="your-client-secret"
220
+ ```
221
+
222
+ ### Managed Identity Configuration (Azure Deployment)
223
+ When deployed to Azure Function, the managed identity is automatically used.
224
+ No environment variables or secrets needed - WAF Security best practice.