Repository: traefik/traefik (language: go)

Issue:
Acme default generated certificate uses a wrong CN
### Welcome!

- [X] Yes, I've searched similar issues on [GitHub](https://github.com/traefik/traefik/issues) and didn't find any.
- [X] Yes, I've searched similar issues on the [Traefik community forum](https://community.traefik.io) and didn't find any.

### What did you do?

We are considering using a `defaultGeneratedCert` in order to enable Acme certificates using an on premises provider.
We tried the following configuration:

```yaml
tls:
  stores:
    default:
      defaultGeneratedCert:
        resolver: customResolver
        domain:
          main: hostname.at.some.domain
          sans:
            - alias.at.other.domain
```

We then expect to get a certificate which Common Name is `hostname.at.some.domain`.


### What did you see instead?

The process runs fine, but the resulting certificate uses `alias.at.other.domain` as the Common Name. `hostname.at.some.domain` is just set as an Alternate Name.

This issue may be related to #10486, which was closed (but should not have been in my opinion, reason why I submit this new one).

We currently have limitations regarding the number of certificates for a given DNS alias, therefore using the hostname as the Common Name makes a *huge* difference for us...

As showed by the logs hereafter (`Loading ACME certificates [alias.at.other.domain hostname.at.some.domain]`), the order of domains is wrong *before* creating the CSR with lego (which states that `// The first domain in domains is used for the CommonName field of the certificate`).


### What version of Traefik are you using?

```console
Version:      2.11.0
Codename:     cheddar
Go version:   go1.22.0
Built:        2024-02-12T15:26:45Z
OS/Arch:      linux/amd64
```

### What is your environment & configuration?

```yaml
tls:
  stores:
    default:
      defaultGeneratedCert:
        resolver: customResolver
        domain:
          main: hostname.at.some.domain
          sans:
            - alias.at.other.domain
```

### If applicable, please paste the log output in DEBUG level

```console
time="2024-04-08T15:20:30Z" level=info msg="Starting provider *acme.Provider"
time="2024-04-08T15:20:30Z" level=debug msg="*acme.Provider provider configuration: {\"email\":\"...\",\"caServer\":\"https://on.premises\",\"storage\":\"/acme/acme.json\",\"keyType\":\"RSA4096\",\"certificatesDuration\":2160,\"dnsChallenge\":{\"provider\":\"exec\",\"delayBeforeCheck\":\"35s\",\"disablePropagationCheck\":true},\"ResolverName\":\"customResolver\",\"store\":{},\"TLSChallengeProvider\":{},\"HTTPChallengeProvider\":{}}"
time="2024-04-08T15:20:30Z" level=debug msg="Attempt to renew certificates \"720h0m0s\" before expiry and check every \"24h0m0s\"" providerName=customResolver.acme ACME CA="..."
time="2024-04-08T15:20:30Z" level=info msg="Testing certificate renew..." providerName=customResolver.acme ACME CA="..."
time="2024-04-08T15:20:30Z" level=debug msg="Configuration received: {\"http\":{},\"tcp\":{},\"udp\":{},\"tls\":{}}" providerName=customResolver.acme
...
time="2024-04-08T15:20:30Z" level=debug msg="No default certificate, fallback to the internal generated certificate" tlsStoreName=default
...
time="2024-04-08T15:20:30Z" level=debug msg="No store is defined to add the certificate MIIDyDCCAbCgAwIBAgIJAOnB/AY94p/gMA0GCSqGSIb3DQEBCw, it will be added to the default store."
time="2024-04-08T15:20:30Z" level=debug msg="Adding certificate for domain(s) 127.0.0.1,localhost"
time="2024-04-08T15:20:31Z" level=error msg="Error while creating certificate store: unable to find certificate for domains \"alias.at.other.domain,hostname.at.some.domain\": falling back to the internal generated certificate" tlsStoreName=default
...
time="2024-04-08T15:20:31Z" level=debug msg="Loading ACME certificates [alias.at.other.domain hostname.at.some.domain]..." ACME CA="..." providerName=customResolver.acme
time="2024-04-08T15:20:35Z" level=debug msg="Serving default certificate for request: \"\""
time="2024-04-08T15:20:35Z" level=debug msg="Building ACME client..." providerName=customResolver.acme
time="2024-04-08T15:20:35Z" level=debug msg="..." providerName=customResolver.acme
time="2024-04-08T15:20:35Z" level=info msg=Register... providerName=customResolver.acme
time="2024-04-08T15:20:35Z" level=debug msg="legolog: [INFO] acme: Registering account for ..."
time="2024-04-08T15:20:36Z" level=debug msg="Using DNS Challenge provider: exec" providerName=customResolver.acme
time="2024-04-08T15:20:36Z" level=debug msg="legolog: [INFO] [alias.at.other.domain, hostname.at.some.domain] acme: Obtaining bundled SAN certificate"
time="2024-04-08T15:20:38Z" level=debug msg="legolog: [INFO] [alias.at.other.domain] AuthURL: https://on.premises:443/lorand-acme/g2-server-acme/authz/Bb1UNlTpxg0J"
time="2024-04-08T15:20:38Z" level=debug msg="legolog: [INFO] [hostname.at.some.domain] AuthURL: https://on.premises:443/lorand-acme/g2-server-acme/authz/0Nzdp5pFcX48"
time="2024-04-08T15:20:38Z" level=debug msg="legolog: [INFO] [alias.at.other.domain] acme: Could not find solver for: http-01"
time="2024-04-08T15:20:38Z" level=debug msg="legolog: [INFO] [alias.at.other.domain] acme: use dns-01 solver"
time="2024-04-08T15:20:38Z" level=debug msg="legolog: [INFO] [hostname.at.some.domain] acme: Could not find solver for: http-01"
time="2024-04-08T15:20:38Z" level=debug msg="legolog: [INFO] [hostname.at.some.domain] acme: use dns-01 solver"
time="2024-04-08T15:20:38Z" level=debug msg="legolog: [INFO] [alias.at.other.domain] acme: Preparing to solve DNS-01"
time="2024-04-08T15:20:40Z" level=debug msg="Serving default certificate for request: \"\""
time="2024-04-08T15:20:43Z" level=debug msg="legolog: 2024/04/08 15:20:38 Creating challenge 'bQgDCnqy4w4rIPj0d-mweb-BkODleThA0SGjB4kjQF8' on DNS alias.at.other.domain (_acme-challenge.alias.at.other.domain.)..."
time="2024-04-08T15:20:43Z" level=debug msg="2024/04/08 15:20:43 ✅"
time="2024-04-08T15:20:43Z" level=debug
time="2024-04-08T15:20:43Z" level=debug msg="legolog: [INFO] [alias.at.other.domain] acme: Trying to solve DNS-01"
time="2024-04-08T15:20:43Z" level=debug msg="legolog: [INFO] [alias.at.other.domain] acme: Checking DNS record propagation using [127.0.0.11:53]"
time="2024-04-08T15:20:45Z" level=debug msg="legolog: [INFO] Wait for propagation [timeout: 1m0s, interval: 2s]"
time="2024-04-08T15:20:45Z" level=debug msg="Delaying 35000000000 rather than validating DNS propagation now." providerName=customResolver.acme
...
time="2024-04-08T15:21:20Z" level=debug msg="legolog: [INFO] [alias.at.other.domain] The server validated our request"
time="2024-04-08T15:21:20Z" level=debug msg="legolog: [INFO] [alias.at.other.domain] acme: Cleaning DNS-01 challenge"
time="2024-04-08T15:21:24Z" level=debug msg="legolog: 2024/04/08 15:21:20 Removing challenge 'bQgDCnqy4w4rIPj0d-mweb-BkODleThA0SGjB4kjQF8' on DNS alias.at.other.domain (_acme-challenge.alias.at.other.domain.)..."
time="2024-04-08T15:21:24Z" level=debug msg="2024/04/08 15:21:24 ✅"
time="2024-04-08T15:21:24Z" level=debug
time="2024-04-08T15:21:24Z" level=debug msg="legolog: [INFO] sequence: wait for 1m0s"
...
time="2024-04-08T15:22:24Z" level=debug msg="legolog: [INFO] [hostname.at.some.domain] acme: Preparing to solve DNS-01"
time="2024-04-08T15:22:25Z" level=debug msg="Serving default certificate for request: \"\""
time="2024-04-08T15:22:28Z" level=debug msg="legolog: 2024/04/08 15:22:24 Creating challenge 'MLfpCCJwGlo5Z3vQT1_FE3qwtkwFk88aeI6Y9yiI8hc' on DNS hostname.at.some.domain (_acme-challenge.hostname.at.some.domain.)..."
time="2024-04-08T15:22:28Z" level=debug msg="2024/04/08 15:22:28 ✅"
time="2024-04-08T15:22:28Z" level=debug
time="2024-04-08T15:22:28Z" level=debug msg="legolog: [INFO] [hostname.at.some.domain] acme: Trying to solve DNS-01"
time="2024-04-08T15:22:28Z" level=debug msg="legolog: [INFO] [hostname.at.some.domain] acme: Checking DNS record propagation using [127.0.0.11:53]"
...
time="2024-04-08T15:22:30Z" level=debug msg="legolog: [INFO] Wait for propagation [timeout: 1m0s, interval: 2s]"
time="2024-04-08T15:22:30Z" level=debug msg="Delaying 35000000000 rather than validating DNS propagation now." providerName=customResolver.acme
...
time="2024-04-08T15:23:06Z" level=debug msg="legolog: [INFO] [hostname.at.some.domain] The server validated our request"
time="2024-04-08T15:23:06Z" level=debug msg="legolog: [INFO] [hostname.at.some.domain] acme: Cleaning DNS-01 challenge"
time="2024-04-08T15:23:09Z" level=debug msg="legolog: 2024/04/08 15:23:06 Removing challenge 'MLfpCCJwGlo5Z3vQT1_FE3qwtkwFk88aeI6Y9yiI8hc' on DNS hostname.at.some.domain (_acme-challenge.hostname.at.some.domain.)..."
time="2024-04-08T15:23:09Z" level=debug msg="2024/04/08 15:23:09 ✅"
time="2024-04-08T15:23:09Z" level=debug
time="2024-04-08T15:23:09Z" level=debug msg="legolog: [INFO] [alias.at.other.domain, hostname.at.some.domain] acme: Validations succeeded; requesting certificates"
...
time="2024-04-08T15:23:16Z" level=debug msg="legolog: [INFO] [alias.at.other.domain] Server responded with a certificate."
time="2024-04-08T15:23:16Z" level=debug msg="Default certificate obtained for domains [alias.at.other.domain hostname.at.some.domain]" providerName=customResolver.acme ACME CA="..."
time="2024-04-08T15:23:16Z" level=debug msg="Adding certificate for domain(s) alias.at.other.domain,hostname.at.some.domain"
time="2024-04-08T15:23:16Z" level=debug msg="No store is defined to add the certificate MIIDyDCCAbCgAwIBAgIJAOnB/AY94p/gMA0GCSqGSIb3DQEBCw, it will be added to the default store."
...
```


Discussion / hints:

Fix patch:
diff --git a/pkg/provider/acme/provider.go b/pkg/provider/acme/provider.go
index 3b4c6d8458..47e3d731d8 100644
--- a/pkg/provider/acme/provider.go
+++ b/pkg/provider/acme/provider.go
@@ -552,8 +552,11 @@ func (p *Provider) resolveDefaultCertificate(ctx context.Context, domains []stri
 
 	p.resolvingDomainsMutex.Lock()
 
-	sort.Strings(domains)
-	domainKey := strings.Join(domains, ",")
+	sortedDomains := make([]string, len(domains))
+	copy(sortedDomains, domains)
+	sort.Strings(sortedDomains)
+
+	domainKey := strings.Join(sortedDomains, ",")
 
 	if _, ok := p.resolvingDomains[domainKey]; ok {
 		p.resolvingDomainsMutex.Unlock()
@@ -947,12 +950,14 @@ func (p *Provider) certExists(validDomains []string) bool {
 	p.certificatesMu.RLock()
 	defer p.certificatesMu.RUnlock()
 
-	sort.Strings(validDomains)
+	sortedDomains := make([]string, len(validDomains))
+	copy(sortedDomains, validDomains)
+	sort.Strings(sortedDomains)
 
 	for _, cert := range p.certificates {
 		domains := cert.Certificate.Domain.ToStrArray()
 		sort.Strings(domains)
-		if reflect.DeepEqual(domains, validDomains) {
+		if reflect.DeepEqual(domains, sortedDomains) {
 			return true
 		}
 	}


Test patch: