Пример #1
0
        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));
            }
        }
Пример #3
0
        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());
        }
Пример #6
0
        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);
        }
Пример #8
0
        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);
            }
        }
Пример #10
0
        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);
        }