- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我目前正在设置一个高可用性 (HA) 环境,其中两个运行 Ubuntu 的 Azure 虚拟机位于标准 Azure 负载均衡器后面。现在我知道标准负载均衡器只是第 4 层,这意味着它无法进行 SSL 卸载。
这两个虚拟机都运行 .NET Core Web API。显然,他们每个人都需要 SSL 证书来处理来自负载均衡器的 SSL 连接。
我知道我可以购买 SSL 证书,然后只需将 Kestrel 设置为在 Web API 本身上使用该证书,但我想要免费证书。我知道另一个选择是使用 nginx 服务器生成证书,然后将证书复制到 Web API,但这意味着我需要每 3 个月重复一次该过程,这非常痛苦,因为这意味着我将需要停机我使 HA 集群离线以更新证书。
有人知道在负载均衡器后面的两个虚拟机上使用 Lets Encrypt 的方法吗?
最佳答案
好吧,我就按照上面的内容来了。它要求我编写一个实用程序,使用 DNS 验证自动更新我的 Lets Encrypt 证书。它使用 Azure DNS 或其他具有 API 的 DNS 提供商非常重要,因为您需要能够使用 API 或与提供商的其他接口(interface)直接修改您的 DNS 记录。
我正在使用 Azure DNS,它为我管理整个域,因此下面的代码适用于 Azure DNS,但您可以修改 API 以与您选择的任何具有某种 API 的提供商合作。
第二部分是不要让我的高可用性 (HA) 集群出现任何停机时间。所以我所做的是将证书写入数据库,然后在虚拟机启动时动态读取它。所以基本上每次 Kestrel 启动时,它都会从数据库读取证书,然后使用它。
<小时/>您需要将以下模型添加到数据库中,以便可以将实际的证书详细信息存储在某处。
public class Certificate
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public string FullChainPem { get; set; }
public string CertificatePfx { get; set; }
public string CertificatePassword { get; set; }
public DateTime CertificateExpiry { get; set; }
public DateTime? CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
}
创建模型后,您需要将其放置在您的上下文中,如下所示:
public DbSet<Certificate> Certificates { get; set; }
在您的应用程序服务器上,您可能希望使用 Kestrel
充当 Web 服务器,然后从数据库动态加载证书。因此,将以下内容添加到您的 CreateWebHostBuilder
中方法。重要的是,这是在 .UseStartup<Startup>()
之后
.UseKestrel(opt = >{
//Get the application services
var applicationServices = opt.ApplicationServices;
//Create and use scope
using(var scope = applicationServices.CreateScope()) {
//Get the database context to work with
var context = scope.ServiceProvider.GetService < DBContext > ();
//Get the certificate
var certificate = context.Certificates.Last();
var pfxBytes = Convert.FromBase64String(certificate.CertificatePfx);
var pfxPassword = certificate.CertificatePassword;
//Create the certificate
var cert = new X509Certificate2(pfxBytes, pfxPassword);
//Listen on the specified IP and port
opt.Listen(IPAddress.Any, 443, listenOpts = >{
//Use HTTPS
listenOpts.UseHttps(cert);
});
}
});
这就是解决方案的核心内容。它处理证书请求、质询、DNS 验证,然后存储证书。它还会自动重新启动 Azure 中使用证书的每个 VM 实例,以便它们提取新证书。
Main
逻辑如下,会检查证书是否需要更新。
static void Main(string[] args) {
while (true) {
//Get the latest certificate in the DB for the servers
var lastCertificate = _db.Certificates.LastOrDefault();
//Check if the expiry date of last certificate is more than a month away
if (lastCertificate != null && (lastCertificate.CertificateExpiry - DateTime.Now).TotalDays > 31) {
//Log out some info
Console.WriteLine($ "[{DateTime.Now}] - Certificate still valid, sleeping for a day.");
//Sleep the thread
Thread.Sleep(TimeSpan.FromDays(1));
}
else {
//Renew the certificates
RenewCertificates();
}
}
}
好吧,这需要经历很多事情,但如果你分解它,它实际上很简单
实际RenewCertificates
方法如下:
/// <summary>
/// Method that will renew the domain certificates and update the database with them
/// </summary>
public static void RenewCertificates() {
Console.WriteLine($ "[{DateTime.Now}] - Starting certificate renewal.");
//Instantiate variables
AcmeContext acme;
IAccountContext account;
//Try and get the setting value for ACME Key
var acmeKey = _db.Settings.FirstOrDefault(s = >s.Key == "ACME");
//Check if acme key is null
if (acmeKey == null) {
//Set the ACME servers to use
#if DEBUG
acme = new AcmeContext(WellKnownServers.LetsEncryptStagingV2);
#else
acme = new AcmeContext(WellKnownServers.LetsEncryptV2);
#endif
//Create the new account
account = acme.NewAccount("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dca5b3a9aeb2bdb1b99ca5b3a9aeb8b3b1bdb5b2f2a8b0b8" rel="noreferrer noopener nofollow">[email protected]</a>", true).Result;
//Save the key to the DB to be used
_db.Settings.Add(new Setting {
Key = "ACME",
Value = acme.AccountKey.ToPem()
});
//Save DB changes
_db.SaveChanges();
}
else {
//Get the account key from PEM
var accountKey = KeyFactory.FromPem(acmeKey.Value);
//Set the ACME servers to use
#if DEBUG
acme = new AcmeContext(WellKnownServers.LetsEncryptStagingV2, accountKey);
#else
acme = new AcmeContext(WellKnownServers.LetsEncryptV2, accountKey);
#endif
//Get the actual account
account = acme.Account().Result;
}
//Create an order for wildcard domain and normal domain
var order = acme.NewOrder(new[] {
"*.yourdomain.tld",
"yourdomain.tld"
}).Result;
//Generate the challenges for the domains
var authorizations = order.Authorizations().Result;
//Error flag
var hasFailed = false;
foreach(var authorization in authorizations) {
//Get the DNS challenge for the authorization
var dnsChallenge = authorization.Dns().Result;
//Get the DNS TXT
var dnsTxt = acme.AccountKey.DnsTxt(dnsChallenge.Token);
Console.WriteLine($ "[{DateTime.Now}] - Received DNS challenge data.");
//Set the DNS record
Azure.SetAcmeTxtRecord(dnsTxt);
Console.WriteLine($ "[{DateTime.Now}] - Updated DNS challenge data.");
Console.WriteLine($ "[{DateTime.Now}] - Waiting 1 minute before checking status.");
dnsChallenge.Validate();
//Wait 1 minute
Thread.Sleep(TimeSpan.FromMinutes(1));
//Check the DNS challenge
var valid = dnsChallenge.Validate().Result;
//If the verification fails set failed flag
if (valid.Status != ChallengeStatus.Valid) hasFailed = true;
}
//Check whether challenges failed
if (hasFailed) {
Console.WriteLine($ "[{DateTime.Now}] - DNS challenge(s) failed, retrying.");
//Recurse
RenewCertificates();
return;
}
else {
Console.WriteLine($ "[{DateTime.Now}] - DNS challenge(s) successful.");
//Generate a private key
var privateKey = KeyFactory.NewKey(KeyAlgorithm.ES256);
//Generate certificate
var cert = order.Generate(new CsrInfo {
CountryName = "ZA",
State = "Gauteng",
Locality = "Pretoria",
Organization = "Your Organization",
OrganizationUnit = "Production",
},
privateKey).Result;
Console.WriteLine($ "[{DateTime.Now}] - Certificate generated successfully.");
//Get the full chain
var fullChain = cert.ToPem();
//Generate password
var pass = Guid.NewGuid().ToString();
//Export the pfx
var pfxBuilder = cert.ToPfx(privateKey);
var pfx = pfxBuilder.Build("yourdomain.tld", pass);
//Create database entry
_db.Certificates.Add(new Certificate {
FullChainPem = fullChain,
CertificatePfx = Convert.ToBase64String(pfx),
CertificatePassword = pass,
CertificateExpiry = DateTime.Now.AddMonths(2)
});
//Save changes
_db.SaveChanges();
Console.WriteLine($ "[{DateTime.Now}] - Database updated with new certificate.");
Console.WriteLine($ "[{DateTime.Now}] - Restarting VMs.");
//Restart the VMS
Azure.RestartAllVms();
}
}
无论我打电话到哪里Azure
您需要编写 API 包装器来设置 DNS TXT 记录,然后才能从托管提供商处重新启动虚拟机。我的全部都是 Azure,所以做起来非常简单。这是 Azure 代码:
/// <summary>
/// Method that will set the TXT record value of the ACME challenge
/// </summary>
/// <param name="txtValue">Value for the TXT record</param>
/// <returns>Whether call was successful or not</returns>
public static bool SetAcmeTxtRecord(string txtValue) {
//Set the zone endpoint
const string url = "https://management.azure.com/subscriptions/{subId}/resourceGroups/{resourceGroup}/providers/Microsoft.Network/dnsZones/{dnsZone}/txt/_acme-challenge?api-version=2018-03-01-preview";
//Authenticate API
AuthenticateApi();
//Build up the body to put
var body = $ "{{\"properties\": {{\"metadata\": {{}},\"TTL\": 225,\"TXTRecords\": [{{\"value\": [\"{txtValue}\"]}}]}}}}";
//Build up the string content
var content = new StringContent(body, Encoding.UTF8, "application/json");
//Create the response
var response = client.PutAsync(url, content).Result;
//Return the response
return response.IsSuccessStatusCode;
}
我希望这能够帮助其他和我遇到同样困境的人。
关于azure - 负载均衡器后面的 .NET Core VMS 上的 SSL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55038772/
我希望能够说这样的话 cd [.fred] 并将我的默认目录放在那里, 和我的提示更改以指示我当前位置的完整路径。 最佳答案 只需输入 cd:==set default 在命令提示符下。你也可以把它放
我想建立一个由两个Docker容器组成的小型环境。我为它们准备了Dockerfile,并使用Docker本身,它们可以正常旋转。但是,当我想在OSX上使用Vagrant时,vagrant up会创建两
我有一个正在运行的测试脚本会产生一些错误,如下所示,我预计会出现这些错误。无论如何我可以阻止它们显示在屏幕上吗?我用 $ write sys$output 如果出现预期错误则显示。 我尝试使用 $ D
我正在尝试找到 VMS 日期到长数据类型背后的转换逻辑。例如,在 RDB 数据库中,日期列是 timesatmp。这些值作为 VMS 日期到长转换进行传递。 日期值:2008-11-13 05:10:
位于 http://h71000.www7.hp.com/doc/731final/documentation/pdf/ovms_731_file_app.pdf 的文档(第 5-1 节)说文件名应该
我的帐户上有一台带有 IIS 的 Windows 服务器和一张 127GB 的操作系统磁盘。我还有另一台 sql 服务器,操作系统磁盘也是 127gb 和 3 个附加磁盘,一个用于临时数据库,另一个用
我的任务是将一些旧的(大约 1986 年)VAX VMS FORTRAN 代码移植到 C++,但遇到了一些障碍。以下两行代码是计算转到的一部分。 WRITE(2'N) (Y (I), I = 1, 5
曾几何时,一群人坐下来用 C 编写了一个应用程序,运行在 VMS 上。在 VAX 上。这是一项相当重要的任务,在 LargeCo 运行相当重要的后端操作。这整个 shebang 工作得很好 以至于 2
我在 vms 中有一个工具 xyz 。我想获取它的安装位置。例如,在 unix 中,我们可以通过使用 其中 命令来实现这一点。所以请帮助我 vms 相当于此命令。 最佳答案 VMS 中没有与 whic
我最近使用5.2进行学习,我想这样尝试: 第一步,为lua构建一个c模块: #include "lua.h" #include "lauxlib.h" #include "lualib.h" #inc
我正在尝试了解云服务(在创建新虚拟机时创建的)的重要性。据我了解,一组虚拟机需要属于同一个云服务才能参与负载平衡。我看不出有任何其他理由将虚拟机分组到单个云服务中。另一方面,为每个虚拟机创建云服务似乎
我正在尝试将 C 源文件从 vms alpha 复制到 Windows 计算机,以便更轻松地编辑代码。 (VMS编辑器只是一个文本编辑器,如果有语法高亮等功能就更好了) 我可以使用 Exceed FT
我试图了解通过 Docker 扩展应用程序的好处。 据我了解;如果我有一个 docker 化的应用程序在 kubernetes 中的单个 docker 容器或 pod 中运行;为了扩展它,即在负载增加
我刚刚开始使用布鲁克林,我正在尝试从 deploying blueprints 获取示例页面完全通过我的 AWS 帐户运行。 Maven 构建已成功完成,我可以使用以下命令从 ~/apache-bro
互联网上有很多关于如何在 unix 中使用 python 创建守护进程的条目,但我找不到任何提及如何在 OpenVMS 中执行此操作的条目。有谁知道如何使用 python 在 OpenVMS 中创建守
这个问题与我的另一个问题有关- boost::bind return a function object which is the argument for a function that requi
另一个复古计算类型的问题...... 我希望有人会记得如何使用 Ada83 (v3.0A) 从 VMS 下的终端进行直接字符 IO。 不幸的是,Ada 的这个旧版本没有在 TEXT_IO 包中实现 G
我的应用程序包含静态链接的 lua 5.2 解释器(并且无法访问代码)。 当我尝试使用下一个代码编写扩展时: #define LUA_LIB #define LUA_BUILD_AS_DLL #inc
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 6年前关闭。 Improve thi
我需要提取订阅中的虚拟机列表,其中还显示每个虚拟机拥有的 CPU 核心,有办法做到这一点吗? 最佳答案 您可以使用下面的PowerShell 脚本来提取虚拟机及其各自的 CPU 核心的列表。 Conn
我是一名优秀的程序员,十分优秀!