caddyserver / caddy

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
https://caddyserver.com
Apache License 2.0
58.26k stars 4.03k forks source link

caddy tls key_type ignores rsa2048 #6574

Closed nusnewob closed 1 month ago

nusnewob commented 1 month ago

I have a caddy instance using Route53 ACME challenge to generate RSA2048 TLS cert for a legacy app, caddy seems to ignore tls { key_type rsa2048 } block.

The caddy docker instance was built with Route53 module for Caddy.

Caddy version

$ caddy version
2024/09/15 10:59:40.301 WARN    failed to set GOMAXPROCS        {"error": "open /sys/fs/cgroup/cpu/cpu.cfs_quota_us: no such file or directory"}
v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=

Dockerfile

FROM caddy:builder AS builder

RUN xcaddy build \
  --with github.com/caddy-dns/route53

FROM caddy:latest

RUN apk --no-cache add curl ca-certificates nss-tools \
  && update-ca-certificates \
  && rm -rf /var/cache/apk/*

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

Caddy config

{
    acme_dns route53
    log {
        format console
        level ERROR
    }
    admin 0.0.0.0:2019 {
        origins 127.0.0.1 localhost 0.0.0.0:2019
    }
    email admin@example.dev
    default_sni web.example.dev
}

web.example.dev {
    root /usr/share/caddy
    file_server
    respond /health 200
}

legacy.example.dev {
    tls {
        key_type rsa2048
    }
    root /usr/share/caddy
    file_server
}

AWS creds were configured correctly in /root/.aws/credentials and cert for web.example.dev was obtained correctly, however cert for legacy.example.dev with block tls { key_type rsa2048 } was ignored, the cert generated uses the same key type as web.example.dev using ed25519

Caddy generates cert for domain with tls { key_type rsa2048 } using key type rsa2048

console output

$ openssl s_client -connect 192.168.2.253:443 -servername legacy.example.dev
CONNECTED(00000003)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = E6
verify return:1
depth=0 CN = legacy.example.dev
verify return:1
---
Certificate chain
 0 s:CN = legacy.example.dev
   i:C = US, O = Let's Encrypt, CN = E6
   a:PKEY: id-ecPublicKey, 256 (bit); sigalg: ecdsa-with-SHA384
   v:NotBefore: Sep 15 09:34:36 2024 GMT; NotAfter: Dec 14 09:34:35 2024 GMT
 1 s:C = US, O = Let's Encrypt, CN = E6
   i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
   a:PKEY: id-ecPublicKey, 384 (bit); sigalg: RSA-SHA256
   v:NotBefore: Mar 13 00:00:00 2024 GMT; NotAfter: Mar 12 23:59:59 2027 GMT
---

Log

2024/09/15 10:50:45.363 INFO    tls.obtain  acquiring lock  {"identifier": "legacy.example.dev"}
2024/09/15 10:50:45.462 INFO    tls.obtain  lock acquired   {"identifier": "legacy.example.dev"}
2024/09/15 10:50:45.462 INFO    tls storage cleaning happened too recently; skipping for now    {"storage": "FileStorage:/data/caddy", "instance": "2a5d3420-b3dd-4f98-83ba-7ab566f0b189", "try_again": "2024/09/16 10:50:45.462", "try_again_in": 86399.9999993}
2024/09/15 10:50:45.462 INFO    tls.obtain  obtaining certificate   {"identifier": "legacy.example.dev"}
2024/09/15 10:50:45.462 INFO    tls finished cleaning storage units
2024/09/15 10:50:45.462 DEBUG   events  event   {"name": "cert_obtaining", "id": "424f06b9-996f-4415-8c5f-2727d3b7af79", "origin": "tls", "data": {"identifier":"legacy.example.dev"}}
2024/09/15 10:50:45.463 DEBUG   tls.obtain  trying issuer 1/2   {"issuer": "acme-v02.api.letsencrypt.org-directory"}
2024/09/15 10:50:45.463 INFO    tls.issuance.acme   waiting on internal rate limiter    {"identifiers": ["legacy.example.dev"], "ca": "https://acme-v02.api.letsencrypt.org/directory", "account": "admin@example.dev"}
2024/09/15 10:50:45.463 INFO    tls.issuance.acme   done waiting on internal rate limiter   {"identifiers": ["legacy.example.dev"], "ca": "https://acme-v02.api.letsencrypt.org/directory", "account": "admin@example.dev"}
2024/09/15 10:50:45.463 INFO    tls.issuance.acme   using ACME account  {"account_id": "https://acme-v02.api.letsencrypt.org/acme/acct/***********", "account_contact": ["mailto:admin@example.dev"]}
2024/09/15 10:50:45.827 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "GET", "url": "https://acme-v02.api.letsencrypt.org/directory", "headers": {"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["746"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:45 GMT"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:45.827 DEBUG   tls.issuance.acme.acme_client   creating order  {"account": "https://acme-v02.api.letsencrypt.org/acme/acct/***********", "identifiers": ["legacy.example.dev"]}
2024/09/15 10:50:45.937 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "HEAD", "url": "https://acme-v02.api.letsencrypt.org/acme/new-nonce", "headers": {"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Date":["Sun, 15 Sep 2024 10:50:45 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["4OmWUlyUVzYlSwlWSjQm3JEnKk54w2XXEd1bOUnjdzvUal7v1n0"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:46.196 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/new-order", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Boulder-Requester":["***********"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["343"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:46 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Location":["https://acme-v02.api.letsencrypt.org/acme/order/***********/***********"],"Replay-Nonce":["fCBw7MtQel7oZIQzn0tvh_DP4TXSZExtv4pybm4elOnfQ2YdFAA"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 201}
2024/09/15 10:50:46.313 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/authz-v3/***********", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Boulder-Requester":["***********"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["515"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:46 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["fCBw7MtQoJvEnZMv2fmVLwKrNF3xlNveYWDrjr8kcPyeGZlISpM"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:46.313 DEBUG   tls.issuance.acme.acme_client   skipping challenge initiation because authorization is not pending  {"identifier": "legacy.example.dev", "authz_status": "valid"}
2024/09/15 10:50:46.313 INFO    tls.issuance.acme.acme_client   authorization finalized {"identifier": "legacy.example.dev", "authz_status": "valid"}
2024/09/15 10:50:46.313 INFO    tls.issuance.acme.acme_client   validations succeeded; finalizing order {"order": "https://acme-v02.api.letsencrypt.org/acme/order/***********/***********"}
2024/09/15 10:50:47.267 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/finalize/***********/***********", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Boulder-Requester":["***********"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["447"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:47 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Location":["https://acme-v02.api.letsencrypt.org/acme/order/***********/***********"],"Replay-Nonce":["fCBw7MtQ7HlWoDhlA-Dwy5MkRQhJlwK4NtF0zhKro-oyydBh9Mo"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:47.395 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["2852"],"Content-Type":["application/pem-certificate-chain"],"Date":["Sun, 15 Sep 2024 10:50:47 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\"","<https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]/1>;rel=\"alternate\""],"Replay-Nonce":["fCBw7MtQHxQNnTsBf3gLosTydRtRPXLrn_j62TykYbXiUCOKrHg"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:47.396 DEBUG   tls.issuance.acme.acme_client   getting renewal info    {"names": ["legacy.example.dev"]}
2024/09/15 10:50:47.513 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "GET", "url": "https://acme-v02.api.letsencrypt.org/draft-ietf-acme-ari-03/renewalInfo/[SOME_RANDOME_STRING]", "headers": {"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["121"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:47 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Retry-After":["21600"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:47.514 INFO    tls.issuance.acme.acme_client   got renewal info    {"names": ["legacy.example.dev"], "window_start": "2024/11/13 10:11:45.333", "window_end": "2024/11/15 10:11:45.333", "selected_time": "2024/11/13 13:45:12.000", "recheck_after": "2024/09/15 16:50:47.514", "explanation_url": ""}
2024/09/15 10:50:47.630 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]/1", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["2283"],"Content-Type":["application/pem-certificate-chain"],"Date":["Sun, 15 Sep 2024 10:50:47 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\"","<https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]/0>;rel=\"alternate\""],"Replay-Nonce":["fCBw7MtQYb2mYVTi6r_SgvmY9msQy7HrZ670OjbaZgkGEJ55Xp8"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:47.630 DEBUG   tls.issuance.acme.acme_client   getting renewal info    {"names": ["legacy.example.dev"]}
2024/09/15 10:50:47.771 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "GET", "url": "https://acme-v02.api.letsencrypt.org/draft-ietf-acme-ari-03/renewalInfo/[SOME_RANDOME_STRING]", "headers": {"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["121"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:47 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Retry-After":["21600"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:47.771 INFO    tls.issuance.acme.acme_client   got renewal info    {"names": ["legacy.example.dev"], "window_start": "2024/11/13 10:11:45.333", "window_end": "2024/11/15 10:11:45.333", "selected_time": "2024/11/15 03:32:18.000", "recheck_after": "2024/09/15 16:50:47.771", "explanation_url": ""}
2024/09/15 10:50:47.771 INFO    tls.issuance.acme.acme_client   successfully downloaded available certificate chains    {"count": 2, "first_url": "https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]"}
2024/09/15 10:50:47.771 DEBUG   tls.issuance.acme   selected certificate chain  {"url": "https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]"}
2024/09/15 10:50:47.772 INFO    tls.obtain  certificate obtained successfully   {"identifier": "legacy.example.dev", "issuer": "acme-v02.api.letsencrypt.org-directory"}
2024/09/15 10:50:47.772 DEBUG   events  event   {"name": "cert_obtained", "id": "b9fefa71-b24e-441a-b978-e674a60a18ff", "origin": "tls", "data": {"certificate_path":"certificates/acme-v02.api.letsencrypt.org-directory/legacy.example.dev/legacy.example.dev.crt","csr_pem":"[SOME_RANDOME_STRING]","identifier":"legacy.example.dev","issuer":"acme-v02.api.letsencrypt.org-directory","metadata_path":"certificates/acme-v02.api.letsencrypt.org-directory/legacy.example.dev/legacy.example.dev.json","private_key_path":"certificates/acme-v02.api.letsencrypt.org-directory/legacy.example.dev/legacy.example.dev.key","renewal":false,"storage_path":"certificates/acme-v02.api.letsencrypt.org-directory/legacy.example.dev"}}
2024/09/15 10:50:47.772 INFO    tls.obtain  releasing lock  {"identifier": "legacy.example.dev"}
2024/09/15 10:50:47.773 DEBUG   tls loading managed certificate {"domain": "legacy.example.dev", "expiration": "2024/12/14 09:52:16.000", "issuer_key": "acme-v02.api.letsencrypt.org-directory", "storage": "FileStorage:/data/caddy"}
2024/09/15 10:50:47.945 DEBUG   tls.cache   added certificate to cache  {"subjects": ["legacy.example.dev"], "expiration": "2024/12/14 09:52:16.000", "managed": true, "issuer_key": "acme-v02.api.letsencrypt.org-directory", "hash": "4d9c52e696575a523b0d18d2522be3a0db926a4cae5fdbe262104c7846eb443a", "cache_size": 31, "cache_capacity": 10000}
2024/09/15 10:50:47.945 DEBUG   events  event   {"name": "cached_managed_cert", "id": "299a86d7-f9c8-41c3-86c7-3952612c78e9", "origin": "tls", "data": {"sans":["legacy.example.dev"]}}
mohammed90 commented 1 month ago

I'm not able to replicate your experience. Here's my config and the log of OpenSSL:

{
    local_certs
    storage file_system ./data
}
localhost {
    tls {
        key_type rsa2048
    }
    respond "Ok"
}
$ openssl s_client -connect 127.0.0.1:443 -servername localhost
Connecting to 127.0.0.1
CONNECTED(00000384)
depth=1 CN=Caddy Local Authority - ECC Intermediate
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0
verify return:1
---
Certificate chain
 0 s:
   i:CN=Caddy Local Authority - ECC Intermediate
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: ecdsa-with-SHA256
   v:NotBefore: Sep 16 07:41:26 2024 GMT; NotAfter: Sep 16 19:41:26 2024 GMT
 1 s:CN=Caddy Local Authority - ECC Intermediate
   i:CN=Caddy Local Authority - 2024 ECC Root
   a:PKEY: id-ecPublicKey, 256 (bit); sigalg: ecdsa-with-SHA256
   v:NotBefore: Sep 16 07:40:49 2024 GMT; NotAfter: Sep 23 07:40:49 2024 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
MIICijCCAi+gAwIBAgIRALSti4Eqh/Bcj1jPS3/vgIYwCgYIKoZIzj0EAwIwMzEx
MC8GA1UEAxMoQ2FkZHkgTG9jYWwgQXV0aG9yaXR5IC0gRUNDIEludGVybWVkaWF0
ZTAeFw0yNDA5MTYwNzQxMjZaFw0yNDA5MTYxOTQxMjZaMAAwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQC4fpbjQ9YIfNhnuf78r2z6HRP7iISc/iYYniWg
3RqieaLYw+42Ze4GtphehXtM10+W4gOrTDNXbMujJTyZipB6PBsKvk8ddpfj3gp2
KClm4bDhfP2RtfAXW+VcLSpwtbvj+x8QoO4LkdNle/C8dNvCKh6WXdiXK1XH7Fn8
+k/RX2xCPfJkOA/ZEwRES0p06cHqNlB9Mgi87rsqeEKEfmA7h4pQDDbjZhR/HjZE
O1c5+L75MfwSVq3qAcZQTshQEraEVYXNfzTR6u718qN80j9shOfxxTuXGgN1DS5i
xvuIJ3GLaZVPmxpmv1r9LVyrIfsb1bq73IdJLvbG2qXRQWR7AgMBAAGjgYswgYgw
DgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAd
BgNVHQ4EFgQUmXyrTElWUXosPFBbZ5s4yUL8e1swHwYDVR0jBBgwFoAUCD80F6zL
sNPbF75yS+ukbNo1+6wwFwYDVR0RAQH/BA0wC4IJbG9jYWxob3N0MAoGCCqGSM49
BAMCA0kAMEYCIQDRvImv6w1SAgQe6Diw2Q04JjCd1549nS6RI0h1jvyzBQIhAJ8r
a1EuaJ1fScnzoLr18J7GhBfyKFw8dOZMtsC52ZUp
-----END CERTIFICATE-----
subject=
issuer=CN=Caddy Local Authority - ECC Intermediate
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1659 bytes and written 388 bytes
Verification error: unable to get local issuer certificate
---
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256
Server public key is 2048 bit
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 20 (unable to get local issuer certificate)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_128_GCM_SHA256
    Session-ID: 6940084ED105811887E02A47F45AC33726F890C4E4D631F320CCF69442C84802
    Session-ID-ctx:
    Resumption PSK: EBC61A79B9B0F217EC2AA6AC956B093437E685DF0579E47D5D250BCD43017F99
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 604800 (seconds)
    TLS session ticket:
    0000 - 2d 13 76 ef 1e fc fa d1-ab 8d 7c c3 dc a4 ed 0e   -.v.......|.....
    0010 - 03 2d 18 33 53 c9 0b 3f-4b e3 34 42 40 4f 09 9b   .-.3S..?K.4B@O..
    0020 - f8 db c1 1c 91 26 8b 11-a9 24 2b db 1e 38 ff 5a   .....&...$+..8.Z
    0030 - 42 9e 11 01 97 eb 0e 6a-34 9a eb 7c 58 16 19 4e   B......j4..|X..N
    0040 - af de 01 3a 8b a9 71 57-14 17 67 41 f1 a2 f6 73   ...:..qW..gA...s
    0050 - 79 8c 73 bc 76 17 57 f5-a2 a7 9c 9a fc 24 70 54   y.s.v.W......$pT
    0060 - 06 4a 81 8a 4a c7 6d ee-0f                        .J..J.m..

    Start Time: 1726472680
    Timeout   : 7200 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
    Extended master secret: no
    Max Early Data: 0
---

Can you help out more with the replication? Let's try with the template, maybe it'll help zero down on the culprit. Ideally, we need to be able to reproduce the bug in the most minimal way possible. This allows us to write regression tests to verify the fix is working. If we can't reproduce it, then you'll have to test our changes for us until it's fixed -- and then we can't add test cases, either.

I've attached a template below that will help make this easier and faster! This will require some effort on your part -- please understand that we will be dedicating time to fix the bug you are reporting if you can just help us understand it and reproduce it easily.

This template will ask for some information you've already provided; that's OK, just fill it out the best you can. :+1: I've also included some helpful tips below the template. Feel free to let me know if you have any questions!

Thank you again for your report, we look forward to resolving it!

Template

## 1. Environment

### 1a. Operating system and version

```
paste here
```

### 1b. Caddy version (run `caddy version` or paste commit SHA)

```
paste here
```

### 1c. Go version (if building Caddy from source; run `go version`)

```
paste here
```

## 2. Description

### 2a. What happens (briefly explain what is wrong)

### 2b. Why it's a bug (if it's not obvious)

### 2c. Log output

```
paste terminal output or logs here
```

### 2d. Workaround(s)

### 2e. Relevant links

## 3. Tutorial (minimal steps to reproduce the bug)

Helpful tips

  1. Environment: Please fill out your OS and Caddy versions, even if you don't think they are relevant. (They are always relevant.) If you built Caddy from source, provide the commit SHA and specify your exact Go version.

  2. Description: Describe at a high level what the bug is. What happens? Why is it a bug? Not all bugs are obvious, so convince readers that it's actually a bug.

    • 2c) Log output: Paste terminal output and/or complete logs in a code block. DO NOT REDACT INFORMATION except for credentials.
    • 2d) Workaround: What are you doing to work around the problem in the meantime? This can help others who encounter the same problem, until we implement a fix.
    • 2e) Relevant links: Please link to any related issues, pull requests, docs, and/or discussion. This can add crucial context to your report.
  3. Tutorial: What are the minimum required specific steps someone needs to take in order to experience the same bug? Your goal here is to make sure that anyone else can have the same experience with the bug as you do. You are writing a tutorial, so make sure to carry it out yourself before posting it. Please:

    • Start with an empty config. Add only the lines/parameters that are absolutely required to reproduce the bug.
    • Do not run Caddy inside containers.
    • Run Caddy manually in your terminal; do not use systemd or other init systems.
    • If making HTTP requests, avoid web browsers. Use a simpler HTTP client instead, like curl.
    • Do not redact any information from your config (except credentials). Domain names are public knowledge and often necessary for quick resolution of an issue!
    • Note that ignoring this advice may result in delays, or even in your issue being closed. 😞 Only actionable issues are kept open, and if there is not enough information or clarity to reproduce the bug, then the report is not actionable.

Example of a tutorial:

Create a config file: ``` { ... } ``` Open terminal and run Caddy: ``` $ caddy ... ``` Make an HTTP request: ``` $ curl ... ``` Notice that the result is ___ but it should be ___.
nusnewob commented 1 month ago

I've replaced my FQDN with legacy.example.dev, I know local_certs works with key_type rsa2048.

1. Environment

1a. Operating system and version

# uname -a
Linux nas 4.4.302+ #69057 SMP Fri Jan 12 17:02:27 CST 2024 x86_64 GNU/Linux synology_v1000_1621+
# docker --version
Docker version 20.10.23, build 876964a

1b. Caddy version (run caddy version or paste commit SHA)

Built from docker image caddy:builder:sha256:d91078aba635bc14741e77a43d3d76be1b7facc6aed92764d85fc20af522a8b2 with github.com/caddy-dns/route53

$ caddy version
2024/09/15 10:59:40.301 WARN    failed to set GOMAXPROCS        {"error": "open /sys/fs/cgroup/cpu/cpu.cfs_quota_us: no such file or directory"}
v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=

1c. Go version (if building Caddy from source; run go version)

N/A

2. Description

2a. What happens (briefly explain what is wrong)

Caddy ignores tls { key_type rsa2048 } block for a valid FQDN uses AWS Route53 ACME challenge and produces cert with default key type ed25519.

2b. Why it's a bug (if it's not obvious)

2c. Log output

2024/09/15 10:50:45.363 INFO    tls.obtain  acquiring lock  {"identifier": "legacy.example.dev"}
2024/09/15 10:50:45.462 INFO    tls.obtain  lock acquired   {"identifier": "legacy.example.dev"}
2024/09/15 10:50:45.462 INFO    tls storage cleaning happened too recently; skipping for now    {"storage": "FileStorage:/data/caddy", "instance": "2a5d3420-b3dd-4f98-83ba-7ab566f0b189", "try_again": "2024/09/16 10:50:45.462", "try_again_in": 86399.9999993}
2024/09/15 10:50:45.462 INFO    tls.obtain  obtaining certificate   {"identifier": "legacy.example.dev"}
2024/09/15 10:50:45.462 INFO    tls finished cleaning storage units
2024/09/15 10:50:45.462 DEBUG   events  event   {"name": "cert_obtaining", "id": "424f06b9-996f-4415-8c5f-2727d3b7af79", "origin": "tls", "data": {"identifier":"legacy.example.dev"}}
2024/09/15 10:50:45.463 DEBUG   tls.obtain  trying issuer 1/2   {"issuer": "acme-v02.api.letsencrypt.org-directory"}
2024/09/15 10:50:45.463 INFO    tls.issuance.acme   waiting on internal rate limiter    {"identifiers": ["legacy.example.dev"], "ca": "https://acme-v02.api.letsencrypt.org/directory", "account": "admin@example.dev"}
2024/09/15 10:50:45.463 INFO    tls.issuance.acme   done waiting on internal rate limiter   {"identifiers": ["legacy.example.dev"], "ca": "https://acme-v02.api.letsencrypt.org/directory", "account": "admin@example.dev"}
2024/09/15 10:50:45.463 INFO    tls.issuance.acme   using ACME account  {"account_id": "https://acme-v02.api.letsencrypt.org/acme/acct/***********", "account_contact": ["mailto:admin@example.dev"]}
2024/09/15 10:50:45.827 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "GET", "url": "https://acme-v02.api.letsencrypt.org/directory", "headers": {"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["746"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:45 GMT"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:45.827 DEBUG   tls.issuance.acme.acme_client   creating order  {"account": "https://acme-v02.api.letsencrypt.org/acme/acct/***********", "identifiers": ["legacy.example.dev"]}
2024/09/15 10:50:45.937 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "HEAD", "url": "https://acme-v02.api.letsencrypt.org/acme/new-nonce", "headers": {"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Date":["Sun, 15 Sep 2024 10:50:45 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["4OmWUlyUVzYlSwlWSjQm3JEnKk54w2XXEd1bOUnjdzvUal7v1n0"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:46.196 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/new-order", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Boulder-Requester":["***********"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["343"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:46 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Location":["https://acme-v02.api.letsencrypt.org/acme/order/***********/***********"],"Replay-Nonce":["fCBw7MtQel7oZIQzn0tvh_DP4TXSZExtv4pybm4elOnfQ2YdFAA"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 201}
2024/09/15 10:50:46.313 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/authz-v3/***********", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Boulder-Requester":["***********"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["515"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:46 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["fCBw7MtQoJvEnZMv2fmVLwKrNF3xlNveYWDrjr8kcPyeGZlISpM"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:46.313 DEBUG   tls.issuance.acme.acme_client   skipping challenge initiation because authorization is not pending  {"identifier": "legacy.example.dev", "authz_status": "valid"}
2024/09/15 10:50:46.313 INFO    tls.issuance.acme.acme_client   authorization finalized {"identifier": "legacy.example.dev", "authz_status": "valid"}
2024/09/15 10:50:46.313 INFO    tls.issuance.acme.acme_client   validations succeeded; finalizing order {"order": "https://acme-v02.api.letsencrypt.org/acme/order/***********/***********"}
2024/09/15 10:50:47.267 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/finalize/***********/***********", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Boulder-Requester":["***********"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["447"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:47 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Location":["https://acme-v02.api.letsencrypt.org/acme/order/***********/***********"],"Replay-Nonce":["fCBw7MtQ7HlWoDhlA-Dwy5MkRQhJlwK4NtF0zhKro-oyydBh9Mo"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:47.395 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["2852"],"Content-Type":["application/pem-certificate-chain"],"Date":["Sun, 15 Sep 2024 10:50:47 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\"","<https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]/1>;rel=\"alternate\""],"Replay-Nonce":["fCBw7MtQHxQNnTsBf3gLosTydRtRPXLrn_j62TykYbXiUCOKrHg"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:47.396 DEBUG   tls.issuance.acme.acme_client   getting renewal info    {"names": ["legacy.example.dev"]}
2024/09/15 10:50:47.513 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "GET", "url": "https://acme-v02.api.letsencrypt.org/draft-ietf-acme-ari-03/renewalInfo/[SOME_RANDOME_STRING]", "headers": {"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["121"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:47 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Retry-After":["21600"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:47.514 INFO    tls.issuance.acme.acme_client   got renewal info    {"names": ["legacy.example.dev"], "window_start": "2024/11/13 10:11:45.333", "window_end": "2024/11/15 10:11:45.333", "selected_time": "2024/11/13 13:45:12.000", "recheck_after": "2024/09/15 16:50:47.514", "explanation_url": ""}
2024/09/15 10:50:47.630 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]/1", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["2283"],"Content-Type":["application/pem-certificate-chain"],"Date":["Sun, 15 Sep 2024 10:50:47 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\"","<https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]/0>;rel=\"alternate\""],"Replay-Nonce":["fCBw7MtQYb2mYVTi6r_SgvmY9msQy7HrZ670OjbaZgkGEJ55Xp8"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:47.630 DEBUG   tls.issuance.acme.acme_client   getting renewal info    {"names": ["legacy.example.dev"]}
2024/09/15 10:50:47.771 DEBUG   tls.issuance.acme.acme_client   http request    {"method": "GET", "url": "https://acme-v02.api.letsencrypt.org/draft-ietf-acme-ari-03/renewalInfo/[SOME_RANDOME_STRING]", "headers": {"User-Agent":["Caddy/2.8.4 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["121"],"Content-Type":["application/json"],"Date":["Sun, 15 Sep 2024 10:50:47 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Retry-After":["21600"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2024/09/15 10:50:47.771 INFO    tls.issuance.acme.acme_client   got renewal info    {"names": ["legacy.example.dev"], "window_start": "2024/11/13 10:11:45.333", "window_end": "2024/11/15 10:11:45.333", "selected_time": "2024/11/15 03:32:18.000", "recheck_after": "2024/09/15 16:50:47.771", "explanation_url": ""}
2024/09/15 10:50:47.771 INFO    tls.issuance.acme.acme_client   successfully downloaded available certificate chains    {"count": 2, "first_url": "https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]"}
2024/09/15 10:50:47.771 DEBUG   tls.issuance.acme   selected certificate chain  {"url": "https://acme-v02.api.letsencrypt.org/acme/cert/[SOME_RANDOME_STRING]"}
2024/09/15 10:50:47.772 INFO    tls.obtain  certificate obtained successfully   {"identifier": "legacy.example.dev", "issuer": "acme-v02.api.letsencrypt.org-directory"}
2024/09/15 10:50:47.772 DEBUG   events  event   {"name": "cert_obtained", "id": "b9fefa71-b24e-441a-b978-e674a60a18ff", "origin": "tls", "data": {"certificate_path":"certificates/acme-v02.api.letsencrypt.org-directory/legacy.example.dev/legacy.example.dev.crt","csr_pem":"[SOME_RANDOME_STRING]","identifier":"legacy.example.dev","issuer":"acme-v02.api.letsencrypt.org-directory","metadata_path":"certificates/acme-v02.api.letsencrypt.org-directory/legacy.example.dev/legacy.example.dev.json","private_key_path":"certificates/acme-v02.api.letsencrypt.org-directory/legacy.example.dev/legacy.example.dev.key","renewal":false,"storage_path":"certificates/acme-v02.api.letsencrypt.org-directory/legacy.example.dev"}}
2024/09/15 10:50:47.772 INFO    tls.obtain  releasing lock  {"identifier": "legacy.example.dev"}
2024/09/15 10:50:47.773 DEBUG   tls loading managed certificate {"domain": "legacy.example.dev", "expiration": "2024/12/14 09:52:16.000", "issuer_key": "acme-v02.api.letsencrypt.org-directory", "storage": "FileStorage:/data/caddy"}
2024/09/15 10:50:47.945 DEBUG   tls.cache   added certificate to cache  {"subjects": ["legacy.example.dev"], "expiration": "2024/12/14 09:52:16.000", "managed": true, "issuer_key": "acme-v02.api.letsencrypt.org-directory", "hash": "4d9c52e696575a523b0d18d2522be3a0db926a4cae5fdbe262104c7846eb443a", "cache_size": 31, "cache_capacity": 10000}
2024/09/15 10:50:47.945 DEBUG   events  event   {"name": "cached_managed_cert", "id": "299a86d7-f9c8-41c3-86c7-3952612c78e9", "origin": "tls", "data": {"sans":["legacy.example.dev"]}}

2d. Workaround(s)

None.

2e. Relevant links

https://github.com/caddy-dns/route53

3. Tutorial (minimal steps to reproduce the bug)

create caddy config

{
    acme_dns route53
}

web.example.dev {
    respond /health 200
}

legacy.example.dev {
    tls {
        key_type rsa2048
    }
    respond "OK"
}

create .aws/credentials with your AWS access and secret key that has permission to update the hosted zone. the actual hosted zone is replaced with example.dev here.

build caddy with Dockerfile


FROM caddy:builder AS builder

RUN xcaddy build \ --with github.com/caddy-dns/route53

FROM caddy:latest

RUN apk --no-cache add curl ca-certificates nss-tools \ && update-ca-certificates \ && rm -rf /var/cache/apk/*

COPY --from=builder /usr/bin/caddy /usr/bin/caddy


> run caddy

docker run -it --rm caddy


> test cert

$ openssl s_client -connect 192.168.2.253:443 -servername legacy.example.dev CONNECTED(00000003) depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = E6 verify return:1 depth=0 CN = legacy.example.dev verify return:1

Certificate chain 0 s:CN = legacy.example.dev i:C = US, O = Let's Encrypt, CN = E6 a:PKEY: id-ecPublicKey, 256 (bit); sigalg: ecdsa-with-SHA384 v:NotBefore: Sep 15 09:34:36 2024 GMT; NotAfter: Dec 14 09:34:35 2024 GMT 1 s:C = US, O = Let's Encrypt, CN = E6 i:C = US, O = Internet Security Research Group, CN = ISRG Root X1 a:PKEY: id-ecPublicKey, 384 (bit); sigalg: RSA-SHA256 v:NotBefore: Mar 13 00:00:00 2024 GMT; NotAfter: Mar 12 23:59:59 2027 GMT

mohammed90 commented 1 month ago

I can't reproduce it. When I specify a fresh site in the Caddyfile with a specific key_type, Caddy uses that key type. The only thing I observed, is that if I change the key type for an existing site, Caddy will not dispose it for a new key of the requested type until the next renewal. So I can only assume that you had the site running before with the default key type, but then changed the config to have that specific key type. I'm torn between working-as-intended or that Caddy should consider the change in key type when reloading config.

One workaround for that is to delete the existing certificate and key and restart Caddy so it'll generate the new key for a fresh certificate.

Any reason for changing the key type?

mholt commented 1 month ago

Thanks for opening an issue and for the details!

So it sounds to me like you expect that the certificate is replaced, with a new key, when the config specifies a different key type than what it is currently using.

That is a reasonable expectation. But we don't do this for two reasons:

1) Obtaining certificates is an expensive operation (in terms of policy) 2) Decoding certs and keys is an expensive operation (in terms of CPU)

So you can imagine what this would do for servers that are handling hundreds of certificates or more (which is quite common). So we defer changes of settings for certificates until when they would normally be renewed. You can force this by deleting the certs from storage, as Mohammed suggested, but I don't recommend this at scale. (Key type changes are very uncommon.)

mholt commented 1 month ago

I'll close this for now, but feel free to continue the discussion and we can reopen if needed.