private async Task WriteSingleItem(SubscriptionScanDetails result, CancellationToken cancellation) { var resultFolder = Path.Combine(this.folderPath, result.Id); if (!Directory.Exists(resultFolder)) { Directory.CreateDirectory(resultFolder); } for (var i = 0; i < result.ResultFiles.Count; i++) { var destPath = Path.Combine(resultFolder, result.ResultFiles[i].FileName); await using (Stream source = File.Open(result.ResultFiles[i].FullPath, FileMode.Open)) { await using Stream destination = File.Create(destPath); await source.CopyToAsync(destination, cancellation); } result.ResultFiles[i].FullPath = destPath; } var metadata = Path.Combine(resultFolder, $"meta.json"); var jsonResult = JsonSerializerWrapper.Serialize(result); await File.WriteAllTextAsync(metadata, jsonResult, cancellation); Logger.Information("{AzureSubscription} scanning result was written to {Folder}", result.Subscription, resultFolder); }
/// <inheritdoc /> public async Task UploadAsync(SubscriptionScanDetails details, CancellationToken cancellation) { Logger.Information("Uploading scan details for {AzureSubscription} with result {ScanResult}", details.Subscription, details.ScanResult); var folder = BlobFolderNameGenerator.ForDate(details.Timestamp); var metadata = await this.UploadAuditResult(details, folder, cancellation); await this.UploadAuditMetadata(folder, metadata, cancellation); await this.UpdateScannerMetadata(cancellation); }
private async Task <string> UploadSingleAuditFile(SubscriptionScanDetails details, string folder, CancellationToken cancellation, ResultFile resultFile) { var auditPath = $"{folder}/{resultFile.FileName}"; Logger.Information("Uploading scan result for {AzureSubscription} to {AuditPath}", details.Subscription, auditPath); var resultUrl = new Uri($"{this.blobCfg.BasePath}/{auditPath}?{this.blobCfg.Sas}"); var resultBlob = new CloudBlockBlob(resultUrl); await resultBlob.UploadFromFileAsync( resultFile.FullPath, AccessCondition.GenerateEmptyCondition(), new BlobRequestOptions { RetryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(10), 3), }, new OperationContext(), cancellation); return(auditPath); }
private async Task <AuditMetadata> UploadAuditResult(SubscriptionScanDetails details, string folder, CancellationToken cancellation) { var metadata = new AuditMetadata { AuditId = Guid.NewGuid().ToString(), ScannerVersion = this.scannerVersion, Periodicity = this.scannerCfg.Periodicity, AzSkVersion = this.azskVersion, Timestamp = ((DateTimeOffset)details.Timestamp).ToUnixTimeSeconds(), }; if (details.ScanResult == ScanResult.Succeeded) { try { var tasks = details .ResultFiles .Select(rf => this.UploadSingleAuditFile(details, folder, cancellation, rf)) .ToArray(); var taskResults = await Task.WhenAll(tasks); metadata.AuditResult = "succeeded"; metadata.AzSkAuditPaths = tasks.Select(i => i.Result).ToArray(); } catch (Exception ex) { Logger.Warning(ex, "Audit result upload failed"); metadata.AuditResult = "upload-failed"; metadata.FailureDescription = ex.Message; } } else { // TODO: add failure description metadata.AuditResult = "audit-failed"; } return(metadata); }
public async Task UploadAsync(SubscriptionScanDetails details, CancellationToken cancellation) { await this.WriteSingleItem(details, cancellation); }
public async Task <SubscriptionScanDetails> Scan(string subscription, DateTime scanDate) { Logger.Information("{AzureSubscription} scan was started", subscription); var customOutputFolder = Path.Combine(ScanResultsFolder, CreateRandomFileName($"{subscription}_", 6)); Directory.CreateDirectory(customOutputFolder); Logger.Information("Output directory is {OutputDirectory}", customOutputFolder); // commands that will be executed by powershell var arguments = $"-File {this.scannerCfg.AuditScriptPath} " + $"-SubscriptionId {subscription} -TenantId {this.scannerCfg.TenantId} " + $"-ServicePrincipalId {this.scannerCfg.ServicePrincipalId} -ServicePrincipalPassword {this.scannerCfg.ServicePrincipalPassword} " + $"-OutputFolder {customOutputFolder} -NonInteractive"; Logger.Debug("Powershell arguments: {StandardError}", arguments); try { var processStartInfo = new ProcessStartInfo { FileName = "powershell", Arguments = arguments, }; var cts = new CancellationTokenSource(TimeSpan.FromMinutes(60)); var processResults = await ProcessEx.RunAsync(processStartInfo, cts.Token); if (processResults.StandardError != null && processResults.StandardError.Length > 0) { Logger.Warning("Errors: {StandardError}", string.Join(Environment.NewLine, processResults.StandardError)); } Logger.Debug("Stdout: {StandardOutput}", string.Join(Environment.NewLine, processResults.StandardOutput)); Logger .Information( "{AzureSubscription} scan was finished with exit code {ExitCode} in {ScanningTime}", subscription, processResults.ExitCode, processResults.RunTime); var result = SubscriptionScanDetails.New(); result.Subscription = subscription; result.ResultFiles = new List <ResultFile>(); // Results directory looks like ./AzSKLogs/Sub_VSE BizSpark/20200211_153220_GRS/ // Log files and json result are located in subfolder "Etc" var dirs = new DirectoryInfo(customOutputFolder).GetDirectories()[0].GetDirectories()[0].GetDirectories(); foreach (var dir in dirs) { result.ResultFiles.Add(await AggregateLogs(dir.GetFileSystemInfos("Etc/*.LOG"), dir)); var report = dir.GetFileSystemInfos("Etc/SecurityEvaluationData*.json").FirstOrDefault(); if (report != null) { result.ResultFiles.Add(new ResultFile(report.Name, report.FullName)); } } if (processResults.ExitCode != 0) { var logs = string.Join(Environment.NewLine, processResults.StandardOutput); Logger.Error("{AzureSubscription} scan failed: {FailedScanLogs}", subscription, logs); result.ScanResult = ScanResult.Failed; } else { Logger.Information("{AzureSubscription} was succeeded", subscription); result.ScanResult = ScanResult.Succeeded; } return(result); } catch (Exception ex) { Log.Error(ex, "{AzureSubscription} scan failed", subscription); var result = SubscriptionScanDetails.New(); result.Subscription = subscription; result.ScanResult = ScanResult.Failed; return(result); } }