Skip to content

Commit ee52a18

Browse files
authored
Merge pull request #414 from Dstack-TEE/dns-max-time
certbot: Support config for max DNS wait time
2 parents 065c6a5 + 7cc7501 commit ee52a18

File tree

9 files changed

+47
-5
lines changed

9 files changed

+47
-5
lines changed

certbot/cli/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ struct Config {
7474
renew_days_before: u64,
7575
/// Renew timeout in seconds
7676
renew_timeout: u64,
77+
/// Maximum time to wait for DNS propagation in seconds
78+
max_dns_wait: u64,
7779
/// Command to run after renewal
7880
#[serde(default)]
7981
renewed_hook: Option<String>,
@@ -91,6 +93,7 @@ impl Default for Config {
9193
renew_interval: 3600,
9294
renew_days_before: 10,
9395
renew_timeout: 120,
96+
max_dns_wait: 300,
9497
renewed_hook: None,
9598
}
9699
}
@@ -125,6 +128,7 @@ fn load_config(config: &PathBuf) -> Result<CertBotConfig> {
125128
let renew_interval = Duration::from_secs(config.renew_interval);
126129
let renew_expires_in = Duration::from_secs(config.renew_days_before * 24 * 60 * 60);
127130
let renew_timeout = Duration::from_secs(config.renew_timeout);
131+
let max_dns_wait = Duration::from_secs(config.max_dns_wait);
128132
let bot_config = CertBotConfig::builder()
129133
.acme_url(config.acme_url)
130134
.cert_dir(workdir.backup_dir())
@@ -137,6 +141,7 @@ fn load_config(config: &PathBuf) -> Result<CertBotConfig> {
137141
.renew_interval(renew_interval)
138142
.renew_timeout(renew_timeout)
139143
.renew_expires_in(renew_expires_in)
144+
.max_dns_wait(max_dns_wait)
140145
.credentials_file(workdir.account_credentials_path())
141146
.auto_set_caa(config.auto_set_caa)
142147
.maybe_renewed_hook(config.renewed_hook)

certbot/src/acme_client.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub struct AcmeClient {
2727
account: Account,
2828
credentials: Credentials,
2929
dns01_client: Dns01Client,
30+
max_dns_wait: Duration,
3031
}
3132

3233
#[derive(Debug, Clone)]
@@ -53,19 +54,28 @@ pub(crate) fn acme_matches(encoded_credentials: &str, acme_url: &str) -> bool {
5354
}
5455

5556
impl AcmeClient {
56-
pub async fn load(dns01_client: Dns01Client, encoded_credentials: &str) -> Result<Self> {
57+
pub async fn load(
58+
dns01_client: Dns01Client,
59+
encoded_credentials: &str,
60+
max_dns_wait: Duration,
61+
) -> Result<Self> {
5762
let credentials: Credentials = serde_json::from_str(encoded_credentials)?;
5863
let account = Account::from_credentials(credentials.credentials).await?;
5964
let credentials: Credentials = serde_json::from_str(encoded_credentials)?;
6065
Ok(Self {
6166
account,
6267
dns01_client,
6368
credentials,
69+
max_dns_wait,
6470
})
6571
}
6672

6773
/// Create a new account.
68-
pub async fn new_account(acme_url: &str, dns01_client: Dns01Client) -> Result<Self> {
74+
pub async fn new_account(
75+
acme_url: &str,
76+
dns01_client: Dns01Client,
77+
max_dns_wait: Duration,
78+
) -> Result<Self> {
6979
let (account, credentials) = Account::create(
7080
&NewAccount {
7181
contact: &[],
@@ -86,6 +96,7 @@ impl AcmeClient {
8696
account,
8797
dns01_client,
8898
credentials,
99+
max_dns_wait,
89100
})
90101
}
91102

@@ -335,18 +346,31 @@ impl AcmeClient {
335346

336347
/// Self check the TXT records for the given challenges.
337348
async fn check_dns(&self, challenges: &[Challenge]) -> Result<()> {
349+
use tracing::warn;
350+
338351
let mut delay = Duration::from_millis(250);
339352
let mut tries = 1u8;
340353

341354
let mut unsettled_challenges = challenges.to_vec();
342355

343356
debug!("Unsettled challenges: {unsettled_challenges:#?}");
344357

358+
let start_time = std::time::Instant::now();
359+
345360
'outer: loop {
346361
use hickory_resolver::AsyncResolver;
347362

348363
sleep(delay).await;
349364

365+
let elapsed = start_time.elapsed();
366+
if elapsed >= self.max_dns_wait {
367+
warn!(
368+
"DNS propagation timeout after {elapsed:?}, max wait time is {max:?}. proceeding anyway as ACME server may have different DNS view",
369+
max = self.max_dns_wait
370+
);
371+
break;
372+
}
373+
350374
let dns_resolver =
351375
AsyncResolver::tokio_from_system_conf().context("failed to create dns resolver")?;
352376

@@ -374,6 +398,8 @@ impl AcmeClient {
374398
debug!(
375399
tries,
376400
domain = &challenge.acme_domain,
401+
elapsed = ?elapsed,
402+
max_wait = ?self.max_dns_wait,
377403
"challenge not found, waiting for {delay:?}"
378404
);
379405
unsettled_challenges.push(challenge);

certbot/src/acme_client/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ async fn new_acme_client() -> Result<AcmeClient> {
1313
);
1414
let credentials =
1515
std::env::var("LETSENCRYPT_CREDENTIAL").expect("LETSENCRYPT_CREDENTIAL not set");
16-
AcmeClient::load(dns01_client, &credentials).await
16+
AcmeClient::load(dns01_client, &credentials, Duration::from_secs(300)).await
1717
}
1818

1919
#[tokio::test]

certbot/src/bot.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub struct CertBotConfig {
3737
renew_timeout: Duration,
3838
renew_expires_in: Duration,
3939
renewed_hook: Option<String>,
40+
max_dns_wait: Duration,
4041
}
4142

4243
impl CertBotConfig {
@@ -55,7 +56,7 @@ async fn create_new_account(
5556
dns01_client: Dns01Client,
5657
) -> Result<AcmeClient> {
5758
info!("creating new ACME account");
58-
let client = AcmeClient::new_account(&config.acme_url, dns01_client)
59+
let client = AcmeClient::new_account(&config.acme_url, dns01_client, config.max_dns_wait)
5960
.await
6061
.context("failed to create new account")?;
6162
let credentials = client
@@ -82,7 +83,7 @@ impl CertBot {
8283
let acme_client = match fs::read_to_string(&config.credentials_file) {
8384
Ok(credentials) => {
8485
if acme_matches(&credentials, &config.acme_url) {
85-
AcmeClient::load(dns01_client, &credentials).await?
86+
AcmeClient::load(dns01_client, &credentials, config.max_dns_wait).await?
8687
} else {
8788
create_new_account(&config, dns01_client).await?
8889
}

certbot/src/bot/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ async fn new_certbot() -> Result<CertBot> {
2525
.renew_interval(Duration::from_secs(30))
2626
.renew_timeout(Duration::from_secs(120))
2727
.renew_expires_in(Duration::from_secs(7772187))
28+
.max_dns_wait(Duration::from_secs(300))
2829
.auto_set_caa(false)
2930
.build();
3031
config.build_bot().await

gateway/dstack-app/builder/entrypoint.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ domain = "*.$SRV_DOMAIN"
119119
renew_interval = "1h"
120120
renew_before_expiration = "10d"
121121
renew_timeout = "5m"
122+
max_dns_wait = "${CERTBOT_MAX_DNS_WAIT:-5m}"
122123
123124
[core.wg]
124125
public_key = "$PUBLIC_KEY"

gateway/dstack-app/deploy-to-vmm.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ GATEWAY_SERVING_ADDR=0.0.0.0:9204
8484
GUEST_AGENT_ADDR=127.0.0.1:9206
8585
WG_ADDR=0.0.0.0:9202
8686
87+
CERTBOT_MAX_DNS_WAIT=5m
88+
8789
# The token used to launch the App
8890
APP_LAUNCH_TOKEN=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
8991
@@ -143,6 +145,7 @@ BOOTNODE_URL=$BOOTNODE_URL
143145
SUBNET_INDEX=$SUBNET_INDEX
144146
APP_LAUNCH_TOKEN=$APP_LAUNCH_TOKEN
145147
RPC_DOMAIN=$RPC_DOMAIN
148+
CERTBOT_MAX_DNS_WAIT=$CERTBOT_MAX_DNS_WAIT
146149
EOF
147150

148151
if [ -n "$APP_COMPOSE_FILE" ]; then

gateway/gateway.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ domain = "*.example.com"
3838
renew_interval = "1h"
3939
renew_before_expiration = "10d"
4040
renew_timeout = "120s"
41+
max_dns_wait = "5m"
4142

4243
[core.wg]
4344
public_key = ""

gateway/src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ pub struct CertbotConfig {
208208
/// Renew timeout
209209
#[serde(with = "serde_duration")]
210210
pub renew_timeout: Duration,
211+
/// Maximum time to wait for DNS propagation
212+
#[serde(with = "serde_duration")]
213+
pub max_dns_wait: Duration,
211214
}
212215

213216
impl CertbotConfig {
@@ -227,6 +230,7 @@ impl CertbotConfig {
227230
.renew_timeout(self.renew_timeout)
228231
.renew_expires_in(self.renew_before_expiration)
229232
.auto_set_caa(self.auto_set_caa)
233+
.max_dns_wait(self.max_dns_wait)
230234
.build()
231235
}
232236

0 commit comments

Comments
 (0)