====== Scenario 2.3: Create Multi-SAN CSR ======
**Category:** [[.:start|Certificate Signing Requests (CSR)]] \\
**Complexity:** *** (Medium-High) \\
**Prerequisites:** Key pair available \\
**Estimated Time:** 10-15 minutes
----
===== Description =====
This scenario describes creating a CSR with **multiple Subject Alternative Names (SANs)**. This is necessary for certificates that need to secure multiple domains, subdomains, or IP addresses.
**Use cases:**
* Multi-domain certificates (SAN certificates)
* Wildcard + explicit domains combined
* Internal + external names
* Load balancer with multiple backends
----
===== SAN Types =====
^ Type ^ GeneralName Tag ^ Example ^ Usage ^
| DNS | dNSName (2) | www.example.com | Websites, APIs |
| IP | iPAddress (7) | 192.168.1.100 | Internal services |
| Email | rfc822Name (1) | admin@example.com | S/MIME |
| URI | uniformResourceIdentifier (6) | https://example.com | SAML, OIDC |
| UPN | otherName (0) | user@domain.local | Windows Auth |
----
===== Code Example (C#) =====
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using var ctx = PqCryptoContext.Initialize();
using var key = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
var dn = new DnBuilder()
.AddCN("example.com") // Primary domain
.AddO("Example GmbH")
.AddC("DE")
.Build();
// Multi-SAN with different types
var extensions = new ExtBuilder()
.SubjectAlternativeName(new[] {
// DNS names
"dns:example.com",
"dns:www.example.com",
"dns:api.example.com",
"dns:app.example.com",
"dns:*.dev.example.com", // Wildcard for dev
// IP addresses (for internal access)
"ip:10.0.0.100",
"ip:192.168.1.50",
// IPv6
"ip:2001:db8::1"
})
.KeyUsage(KeyUsageFlags.DigitalSignature | KeyUsageFlags.KeyEncipherment)
.ExtendedKeyUsage(ExtKeyUsage.ServerAuth)
.Build();
var csr = ctx.CreateCertificateRequest(key, dn, extensions);
// Output all SANs
Console.WriteLine("Subject Alternative Names:");
foreach (var san in csr.SubjectAlternativeNames)
{
Console.WriteLine($" - {san}");
}
File.WriteAllText("multi-san.csr.pem", csr.ToPem());
----
===== Combining Wildcard + Explicit =====
var extensions = new ExtBuilder()
.SubjectAlternativeName(new[] {
"dns:example.com", // Root domain (wildcard does not cover this!)
"dns:*.example.com", // All 1st level subdomains
"dns:*.api.example.com", // API subdomains
"dns:legacy.old-domain.com" // Alternative domain
})
.Build();
**Important:** Wildcards (''*.example.com'') only cover one level and not the root domain itself! Therefore always specify both ''example.com'' AND ''*.example.com''.
----
===== Kubernetes / Cloud-Native =====
var extensions = new ExtBuilder()
.SubjectAlternativeName(new[] {
// Kubernetes Service DNS
"dns:my-service",
"dns:my-service.default",
"dns:my-service.default.svc",
"dns:my-service.default.svc.cluster.local",
// Headless Service (Pod DNS)
"dns:*.my-service.default.svc.cluster.local",
// External Ingress Domain
"dns:api.example.com"
})
.Build();
----
===== Limits and Best Practices =====
^ Aspect ^ Recommendation ^ Reason ^
| Number of SANs | Max. 100 | Performance, certificate size |
| Wildcard levels | Only 1 level | RFC 6125 restriction |
| IP addresses | Only when necessary | IPs change more frequently |
| Internal names | Separate certificates | Security separation |
----
===== Related Scenarios =====
^ Relationship ^ Scenario ^ Description ^
| **Next Step** | [[en:int:pqcrypt:szenarien:zertifikate:server_cert|3.1 Server Certificate]] | Sign CSR |
| **Alternative** | [[en:int:pqcrypt:szenarien:zertifikate:wildcard_cert|3.5 Wildcard Certificate]] | Wildcard only |
| **Foundation** | [[.:csr_server|2.1 Server CSR]] | Simple server CSR |
----
<< [[.:csr_client|<- 2.2 Client CSR]] | [[.:start|^ CSR Overview]] | [[.:csr_verarbeiten|2.4 Process CSR ->]] >>
{{tag>scenario csr san multi-domain wildcard}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//