public async Task IssueCertificate([OrchestrationTrigger] DurableOrchestrationContext context) { var dnsNames = context.GetInput <string[]>(); var proxy = context.CreateActivityProxy <ISharedFunctions>(); // 前提条件をチェック await proxy.Dns01Precondition(dnsNames); // 新しく ACME Order を作成する var orderDetails = await proxy.Order(dnsNames); // 複数の Authorizations を処理する var challenges = new List <ChallengeResult>(); foreach (var authorization in orderDetails.Payload.Authorizations) { // ACME Challenge を実行 var result = await proxy.Dns01Authorization((authorization, context.ParentInstanceId ?? context.InstanceId)); // Azure DNS で正しくレコードが引けるか確認 await proxy.CheckDnsChallenge(result); challenges.Add(result); } // ACME Answer を実行 await proxy.AnswerChallenges(challenges); // Order のステータスが ready になるまで 60 秒待機 await proxy.CheckIsReady(orderDetails); await proxy.FinalizeOrder((dnsNames, orderDetails)); }
public async Task RenewCertificates([OrchestrationTrigger] DurableOrchestrationContext context, ILogger log) { var activity = context.CreateActivityProxy <ISharedFunctions>(); var certificates = await activity.GetCertificates(context.CurrentUtcDateTime); if (certificates.Count == 0) { log.LogInformation("Certificates are not found"); return; } foreach (var certificate in certificates) { log.LogInformation($"{certificate.Id} - {certificate.Attributes.Expires}"); string frontdoorName = ""; if (certificate.Tags.ContainsKey("FrontDoor")) { frontdoorName = certificate.Tags["FrontDoor"]; } await context.CallSubOrchestratorAsync(nameof(SharedFunctions.IssueCertificate), (certificate.Policy.X509CertificateProperties.SubjectAlternativeNames.DnsNames, frontdoorName)); } }
public async Task IssueCertificate([OrchestrationTrigger] DurableOrchestrationContext context) { var(dnsNames, frontdoorName) = context.GetInput <(string[], string)>(); var activity = context.CreateActivityProxy <ISharedFunctions>(); await activity.Dns01Precondition(dnsNames); // ACME Order var orderDetails = await activity.Order(dnsNames); // Authorizations var challenges = new List <ChallengeResult>(); foreach (var authorization in orderDetails.Payload.Authorizations) { // ACME Challenge var result = await activity.Dns01Authorization((authorization, context.ParentInstanceId ?? context.InstanceId)); // Azure DNS await activity.CheckDnsChallenge(result); challenges.Add(result); } // ACME Answer await activity.AnswerChallenges(challenges); // Order ready await activity.CheckIsReady(orderDetails); await activity.FinalizeOrder((dnsNames, orderDetails, frontdoorName)); }
public async Task <IList <AzureFrontDoor> > GetFrontDoors([OrchestrationTrigger] DurableOrchestrationContext context) { var activity = context.CreateActivityProxy <ISharedFunctions>(); var frontdoors = await activity.GetAllFDoors(); return(frontdoors.ToArray()); }
public async Task <IList <string> > GetDnsZones([OrchestrationTrigger] DurableOrchestrationContext context) { var activity = context.CreateActivityProxy <ISharedFunctions>(); var zones = await activity.GetZones(); return(zones.Select(x => x.Name).ToArray()); }
public async Task <IList <AzureFrontDoor> > GetFrontDoors([OrchestrationTrigger] DurableOrchestrationContext context) { var activity = context.CreateActivityProxy <ISharedFunctions>(); var frontdoors = await activity.GetAllFDoors(); frontdoors.Insert(0, new AzureFrontDoor("#NO-FD-2048#", new List <string>())); frontdoors.Insert(0, new AzureFrontDoor("#NO-FD-4096#", new List <string>())); frontdoors.Insert(0, new AzureFrontDoor("#NO-FD-EXP-2048#", new List <string>())); frontdoors.Insert(0, new AzureFrontDoor("#NO-FD-EXP-4096#", new List <string>())); return(frontdoors.ToArray()); }
public async Task RunOrchestrator([OrchestrationTrigger] DurableOrchestrationContext context, ILogger log) { var proxy = context.CreateActivityProxy <ISharedFunctions>(); // 期限切れまで 30 日以内の証明書を取得する var certificates = await proxy.GetCertificates(context.CurrentUtcDateTime); foreach (var certificate in certificates) { log.LogInformation($"{certificate.SubjectName} - {certificate.ExpirationDate}"); } // 更新対象となる証明書がない場合は終わる if (certificates.Count == 0) { log.LogInformation("Certificates are not found"); return; } // App Service を取得 var sites = await proxy.GetSites(); var tasks = new List <Task>(); // サイト単位で証明書の更新を行う foreach (var site in sites) { // 期限切れが近い証明書がバインドされているか確認 var boundCertificates = certificates.Where(x => site.HostNameSslStates.Any(xs => xs.Thumbprint == x.Thumbprint)) .ToArray(); // 対象となる証明書が存在しない場合はスキップ if (boundCertificates.Length == 0) { continue; } // 証明書の更新処理を開始 tasks.Add(context.CallSubOrchestratorAsync(nameof(RenewSiteCertificates), (site, boundCertificates))); } // サブオーケストレーターの完了を待つ await Task.WhenAll(tasks); }
public async Task RunOrchestrator([OrchestrationTrigger] DurableOrchestrationContext context, ILogger log) { var proxy = context.CreateActivityProxy <ISharedFunctions>(); // 期限切れまで 30 日以内の証明書を取得する var certificates = await proxy.GetCertificates(context.CurrentUtcDateTime); foreach (var certificate in certificates) { log.LogInformation($"{certificate.SubjectName} - {certificate.ExpirationDate}"); } // 対象となる証明書がない場合は終わる if (certificates.Count == 0) { log.LogInformation("Certificates are not found"); return; } // App Service を取得 var sites = await proxy.GetSites(); // App Service にバインド済み証明書のサムプリントを取得 var boundCertificates = sites.SelectMany(x => x.HostNameSslStates.Select(xs => xs.Thumbprint)) .ToArray(); var tasks = new List <Task>(); // バインドされていない証明書を削除 foreach (var certificate in certificates.Where(x => !boundCertificates.Contains(x.Thumbprint))) { tasks.Add(proxy.DeleteCertificate(certificate)); } // アクティビティの完了を待つ await Task.WhenAll(tasks); }
public async Task RunOrchestrator([OrchestrationTrigger] DurableOrchestrationContext context, ILogger log) { var proxy = context.CreateActivityProxy <ISharedFunctions>(); // 期限切れまで 30 日以内の証明書を取得する var certificates = await proxy.GetCertificates(context.CurrentUtcDateTime); // 更新対象となる証明書がない場合は終わる if (certificates.Count == 0) { log.LogInformation("Certificates are not found"); return; } // 証明書の更新を行う foreach (var certificate in certificates) { log.LogInformation($"{certificate.Id} - {certificate.Attributes.Expires}"); // 証明書の更新処理を開始 await context.CallSubOrchestratorAsync(nameof(SharedFunctions.IssueCertificate), certificate.Policy.X509CertificateProperties.SubjectAlternativeNames.DnsNames); } }
public async Task <IList <ResourceGroupInformation> > RunOrchestrator([OrchestrationTrigger] DurableOrchestrationContext context) { var proxy = context.CreateActivityProxy <ISharedFunctions>(); // App Service を取得 var sites = await proxy.GetSites(); var certificates = await proxy.GetAllCertificates(); var result = new List <ResourceGroupInformation>(); foreach (var item in sites.ToLookup(x => x.ResourceGroup)) { var resourceGroup = new ResourceGroupInformation { Name = item.Key, Sites = new List <SiteInformation>() }; foreach (var site in item.ToLookup(x => x.SplitName().siteName)) { var siteInformation = new SiteInformation { Name = site.Key, Slots = new List <SlotInformation>() }; foreach (var slot in site) { var(_, slotName) = slot.SplitName(); var hostNameSslStates = slot.HostNameSslStates .Where(x => !x.Name.EndsWith(".azurewebsites.net")); var slotInformation = new SlotInformation { Name = slotName ?? "production", Domains = hostNameSslStates.Select(x => new DomainInformation { Name = x.Name, Issuer = certificates.FirstOrDefault(xs => xs.Thumbprint == x.Thumbprint)?.Issuer ?? "None" }).ToArray() }; if (slotInformation.Domains.Count != 0) { siteInformation.Slots.Add(slotInformation); } } if (siteInformation.Slots.Count != 0) { resourceGroup.Sites.Add(siteInformation); } } if (resourceGroup.Sites.Count != 0) { result.Add(resourceGroup); } } return(result); }
public async Task AddCertificate([OrchestrationTrigger] DurableOrchestrationContext context, ILogger log) { var request = context.GetInput <AddCertificateRequest>(); var activity = context.CreateActivityProxy <ISharedFunctions>(); var site = await activity.GetSite((request.ResourceGroupName, request.SiteName, request.SlotName)); if (site == null) { log.LogError($"{request.SiteName} is not found"); return; } var hostNameSslStates = site.HostNameSslStates .Where(x => request.Domains.Contains(x.Name)) .ToArray(); if (hostNameSslStates.Length != request.Domains.Length) { foreach (var hostName in request.Domains.Except(hostNameSslStates.Select(x => x.Name))) { log.LogError($"{hostName} is not found"); } return; } // ワイルドカード、コンテナ、Linux の場合は DNS-01 を利用する var useDns01Auth = request.Domains.Any(x => x.StartsWith("*")) || site.Kind.Contains("container") || site.Kind.Contains("linux"); // 前提条件をチェック if (useDns01Auth) { await activity.Dns01Precondition(request.Domains); } else { await activity.Http01Precondition(site); } // 新しく ACME Order を作成する var orderDetails = await activity.Order(request.Domains); // 複数の Authorizations を処理する var challenges = new List <ChallengeResult>(); foreach (var authorization in orderDetails.Payload.Authorizations) { ChallengeResult result; // ACME Challenge を実行 if (useDns01Auth) { // DNS-01 を使う result = await activity.Dns01Authorization((authorization, context.ParentInstanceId ?? context.InstanceId)); // Azure DNS で正しくレコードが引けるか確認 await activity.CheckDnsChallenge(result); } else { // HTTP-01 を使う result = await activity.Http01Authorization((site, authorization)); // HTTP で正しくアクセスできるか確認 await activity.CheckHttpChallenge(result); } challenges.Add(result); } // ACME Answer を実行 await activity.AnswerChallenges(challenges); // Order のステータスが ready になるまで 60 秒待機 await activity.CheckIsReady(orderDetails); // Order の最終処理を実行し PFX を作成 var(thumbprint, pfxBlob) = await activity.FinalizeOrder((request.Domains, orderDetails)); await activity.UpdateCertificate((site, $"{request.Domains[0]}-{thumbprint}", pfxBlob)); foreach (var hostNameSslState in hostNameSslStates) { hostNameSslState.Thumbprint = thumbprint; hostNameSslState.SslState = request.UseIpBasedSsl ?? false ? SslState.IpBasedEnabled : SslState.SniEnabled; hostNameSslState.ToUpdate = true; } await activity.UpdateSiteBinding(site); }