Skip to content

Commit

Permalink
common name not mandatory anymore
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinWeindel committed Nov 16, 2023
1 parent a52873e commit 771623f
Show file tree
Hide file tree
Showing 14 changed files with 114 additions and 44 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ See also [examples/40-ingress-echoheaders.yaml](./examples/40-ingress-echoheader
spec:
tls:
# Gardener managed default domain.
# The first host is used as common name and must not exceed 64 characters
# The first host is used as common name if it does not exceed 64 characters
- hosts:
- test.ingress.<GARDENER-CLUSTER>.<GARDENER-PROJECT>.shoot.example.com
# Certificate and private key reside in this secret.
Expand Down Expand Up @@ -540,7 +540,7 @@ spec:
```

The annotation `cert.gardener.cloud/commonname` is optional. If not specified, the first name of the annotation
`dns.gardener.cloud/dnsnames` is used as common name. It is useful to specify it explicitly, if no `DNSEntry`
`dns.gardener.cloud/dnsnames` is used as common name if it does not exceed 64 characters. It is useful to specify it explicitly, if no `DNSEntry`
should be created for the common name by the dns-controller-manager.
A typical use case is if the common name (limited to 64 characters) is set only to
deal with real domain names specified with `dns.gardener.cloud/dnsnames` which are longer than 64 characters.
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ require (
software.sslmate.com/src/go-pkcs12 v0.2.0
)

replace github.com/go-acme/lego/v4 => github.com/MartinWeindel/lego/v4 v4.4.1-0.20231116095906-a41bce273050

require (
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzS
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/MartinWeindel/lego/v4 v4.4.1-0.20231116095906-a41bce273050 h1:NTOdxgykaXDVawZHM0E9M6rY0MWqEaJTpuVTOWJ1i8U=
github.com/MartinWeindel/lego/v4 v4.4.1-0.20231116095906-a41bce273050/go.mod h1:mBT2JBJIb8yL6QaksGiAsHcO1hrOMsmQQFtQXN+H7yc=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/ahmetb/gen-crd-api-reference-docs v0.3.0 h1:+XfOU14S4bGuwyvCijJwhhBIjYN+YXS18jrCY2EzJaY=
Expand Down Expand Up @@ -42,8 +44,6 @@ github.com/gardener/controller-manager-library v0.2.1-0.20231116080219-8cf0e5458
github.com/gardener/controller-manager-library v0.2.1-0.20231116080219-8cf0e5458fdc/go.mod h1:aepVXNhGH90BjVr9IGDACutA2Kqy9/2rqZZuE2FqJMo=
github.com/gardener/external-dns-management v0.15.3 h1:w7DSzUQY3iC4bKAy4RoP2Lmt/kKYAhpDEZDZr1lxluY=
github.com/gardener/external-dns-management v0.15.3/go.mod h1:8Bvwsirq6BsUiCL1wEE0i2yj+BALOCI6TPOru/+ozeU=
github.com/go-acme/lego/v4 v4.14.0 h1:/skZoRHgVh0d2RK7l1g3Ch8HqeqP9LB8ZEjLdGEpcDE=
github.com/go-acme/lego/v4 v4.14.0/go.mod h1:zjmvNCDLGz7GrC1OqdVpVmZFKSRabEDtWbdzmcpBsGo=
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/cert/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type Certificate struct {
// CertificateSpec is the spec of the certificate to request.
type CertificateSpec struct {
// CommonName is the CN for the certificate (max. 64 chars).
// +optional
// +kubebuilder:validation:MaxLength=64
CommonName *string `json:"commonName,omitempty"`
// DNSNames are the optional additional domain names of the certificate.
Expand Down
15 changes: 12 additions & 3 deletions pkg/cert/legobridge/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,10 @@ func (o *obtainer) ObtainACME(input ObtainInput) error {
certificates, err = renew(client, input.RenewCert)
} else {
if input.CSR == nil {
domains := append([]string{*input.CommonName}, input.DNSNames...)
domains := input.DNSNames
if input.CommonName != nil {
domains = append([]string{*input.CommonName}, domains...)
}
certificates, err = obtainForDomains(client, domains, input.AlwaysDeactivateAuthorizations, input.PreferredChain)
} else {
certificates, err = obtainForCSR(client, input.CSR, input.AlwaysDeactivateAuthorizations, input.PreferredChain)
Expand Down Expand Up @@ -333,13 +336,19 @@ func (o *obtainer) releasePending(input ObtainInput) {

func (o *obtainer) collectDomainNames(input ObtainInput) ([]string, error) {
if input.CSR == nil {
return append([]string{*input.CommonName}, input.DNSNames...), nil
if input.CommonName != nil {
return append([]string{*input.CommonName}, input.DNSNames...), nil
}
return input.DNSNames, nil
}
cn, san, err := utils.ExtractCommonNameAnDNSNames(input.CSR)
if err != nil {
return nil, err
}
return append([]string{*cn}, san...), nil
if cn != nil {
return append([]string{*cn}, san...), nil
}
return san, nil
}

// CertificatesToSecretData converts a certificate resource to secret data.
Expand Down
3 changes: 2 additions & 1 deletion pkg/cert/legobridge/pki.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"time"

"github.com/go-acme/lego/v4/certificate"
"k8s.io/utils/pointer"
)

var (
Expand Down Expand Up @@ -164,7 +165,7 @@ func createCertReq(input ObtainInput) (*x509.CertificateRequest, error) {
Version: 3,
PublicKeyAlgorithm: DefaultPubKeyAlgo,
Subject: pkix.Name{
CommonName: *input.CommonName,
CommonName: pointer.StringDeref(input.CommonName, ""),
Country: subjectCA.Country,
Organization: subjectCA.Organization,
OrganizationalUnit: subjectCA.OrganizationalUnit,
Expand Down
21 changes: 13 additions & 8 deletions pkg/cert/source/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,12 @@ func (r *sourceReconciler) Deleted(logger logger.LogContext, key resources.Clust
failed := false
for _, s := range r.Slaves().GetByOwnerKey(key) {
err := s.Delete()
commonName := certutils.Certificate(s).SafeCommonName()
firstDNSName := certutils.Certificate(s).SafeFirstDNSName()
if err != nil && !errors.IsNotFound(err) {
logger.Warnf("cannot delete certificate %s(%s): %s", s.ObjectName(), commonName, err)
logger.Warnf("cannot delete certificate %s(%s): %s", s.ObjectName(), firstDNSName, err)
failed = true
} else {
logger.Infof("delete certificate for vanished %s(%s)", s.ObjectName(), commonName)
logger.Infof("delete certificate for vanished %s(%s)", s.ObjectName(), firstDNSName)
}
}
if failed {
Expand All @@ -276,11 +276,11 @@ func (r *sourceReconciler) Delete(logger logger.LogContext, obj resources.Object
failed := false
logger.Infof("certificate source is deleting -> delete certificate")
for _, s := range r.Slaves().GetByOwner(obj) {
commonName := certutils.Certificate(s).SafeCommonName()
logger.Infof("delete certificate %s(%s)", s.ObjectName(), commonName)
firstDNSName := certutils.Certificate(s).SafeFirstDNSName()
logger.Infof("delete certificate %s(%s)", s.ObjectName(), firstDNSName)
err := s.Delete()
if err != nil && !errors.IsNotFound(err) {
logger.Warnf("cannot delete certificate %s for %s: %s", s.ObjectName(), commonName, err)
logger.Warnf("cannot delete certificate %s for %s: %s", s.ObjectName(), firstDNSName, err)
failed = true
}
}
Expand Down Expand Up @@ -312,8 +312,13 @@ func (r *sourceReconciler) createEntryFor(logger logger.LogContext, obj resource
resources.SetAnnotation(cert, AnnotClass, r.targetclass)
}
if len(info.Domains) > 0 {
cert.Spec.CommonName = &info.Domains[0]
cert.Spec.DNSNames = info.Domains[1:]
if len(info.Domains[0]) <= 64 {
cert.Spec.CommonName = &info.Domains[0]
cert.Spec.DNSNames = info.Domains[1:]
} else {
cert.Spec.CommonName = nil
cert.Spec.DNSNames = info.Domains
}
}
if info.IssuerName != nil {
parts := strings.SplitN(*info.IssuerName, "/", 2)
Expand Down
49 changes: 32 additions & 17 deletions pkg/cert/utils/utils_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,39 +48,49 @@ func (o *CertificateObject) Status() *api.CertificateStatus {
return &o.Certificate().Status
}

// SafeCommonName return the common name or "".
func (o *CertificateObject) SafeCommonName() string {
// SafeFirstDNSName returns the first DNS name (common name if set) or "".
func (o *CertificateObject) SafeFirstDNSName() string {
cn := o.Spec().CommonName
if cn == nil {
cn = o.Status().CommonName
if cn != nil {
return *cn
}
if cn == nil {
return ""

if len(o.Spec().DNSNames) > 0 {
return o.Spec().DNSNames[0]
}

cn = o.Status().CommonName
if cn != nil {
return *cn
}

if len(o.Status().DNSNames) > 0 {
return o.Status().DNSNames[0]
}
return *cn

return ""
}

////////////////////////////////////////

// ExtractDomains collects CommonName and DNSNames directly from spec or from CSR.
// The first item is the common name
// The first item is the common name if provided.
func ExtractDomains(spec *api.CertificateSpec) ([]string, error) {
var err error
cn := spec.CommonName
if cn == nil || *cn == "" {
return nil, fmt.Errorf("missing common name")
}
dnsNames := spec.DNSNames
if spec.CommonName != nil {
if spec.CommonName != nil || len(spec.DNSNames) > 0 {
if spec.CSR != nil {
return nil, fmt.Errorf("cannot specify both commonName and csr")
}
if len(spec.DNSNames) >= 100 {
return nil, fmt.Errorf("invalid number of DNS names: %d (max 99)", len(spec.DNSNames))
}
count := utf8.RuneCount([]byte(*spec.CommonName))
if count > 64 {
return nil, fmt.Errorf("the Common Name is limited to 64 characters (X.509 ASN.1 specification), but first given domain %s has %d characters", *spec.CommonName, count)
if spec.CommonName != nil {
count := utf8.RuneCount([]byte(*spec.CommonName))
if count > 64 {
return nil, fmt.Errorf("the Common Name is limited to 64 characters (X.509 ASN.1 specification), but first given domain %s has %d characters", *spec.CommonName, count)
}
}
} else {
if spec.CSR == nil {
Expand All @@ -92,7 +102,10 @@ func ExtractDomains(spec *api.CertificateSpec) ([]string, error) {
}
}

return append([]string{*cn}, dnsNames...), nil
if cn != nil {
dnsNames = append([]string{*cn}, dnsNames...)
}
return dnsNames, nil
}

// ExtractCommonNameAnDNSNames extracts values from a CSR (Certificate Signing Request).
Expand All @@ -103,7 +116,9 @@ func ExtractCommonNameAnDNSNames(csr []byte) (cn *string, san []string, err erro
return
}
cnvalue := certificateRequest.Subject.CommonName
cn = &cnvalue
if cnvalue != "" {
cn = &cnvalue
}
san = certificateRequest.DNSNames[:]
for _, ip := range certificateRequest.IPAddresses {
san = append(san, ip.String())
Expand Down
8 changes: 8 additions & 0 deletions pkg/controller/issuer/core/support_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ var _ = Describe("Support", func() {
Expect(key.Cluster()).To(Equal(certutils.ClusterTarget))
Expect(key.Namespace()).To(Equal(namespace1))

spec2b := &api.CertificateSpec{
DNSNames: []string{"foo.sel1t.example.com"},
}
key = support.IssuerClusterObjectKey("foo", spec2b)
Expect(key.Name()).To(Equal("issuer1"))
Expect(key.Cluster()).To(Equal(certutils.ClusterTarget))
Expect(key.Namespace()).To(Equal(namespace1))

spec3 := &api.CertificateSpec{
CommonName: pointer.String("bar.example.com"),
IssuerRef: &api.IssuerRef{
Expand Down
23 changes: 22 additions & 1 deletion test/functional/basics.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,20 @@ spec:
secretName: cert4-secret
issuerRef:
name: {{.Name}}
---
apiVersion: cert.gardener.cloud/v1alpha1
kind: Certificate
metadata:
name: cert5
namespace: {{.Namespace}}
spec:
commonName:
dnsNames:
- cert5.very-very-very-very-very-very-very-very-very-very-very-long.{{.Domain}} # more than 64 chars
- cert5.{{.Domain}}
secretName: cert5-secret
issuerRef:
name: {{.Name}}
`

var revoke2Template = `
Expand Down Expand Up @@ -224,7 +238,7 @@ func functestbasics(cfg *config.Config, iss *config.IssuerConfig) {
Ω(err).Should(BeNil())

entryNames := []string{}
for _, name := range []string{"1", "2", "2b", "3"} {
for _, name := range []string{"1", "2", "2b", "3", "5"} {
entryNames = append(entryNames, entryName(iss, name))
}
err = u.AwaitCertReady(entryNames...)
Expand Down Expand Up @@ -275,6 +289,13 @@ func functestbasics(cfg *config.Config, iss *config.IssuerConfig) {
"expirationDate": HavePrefix("20"),
}),
}),
entryName(iss, "5"): MatchKeys(IgnoreExtras, Keys{
"status": MatchKeys(IgnoreExtras, Keys{
"dnsNames": And(HaveLen(2), ContainElements(dnsName(iss, "cert5.very-very-very-very-very-very-very-very-very-very-very-long"), dnsName(iss, "cert5"))),
"state": Equal("Ready"),
"expirationDate": HavePrefix("20"),
}),
}),
}))

By("check keystores in cert3", func() {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ github.com/gardener/controller-manager-library/pkg/utils/pkiutil
github.com/gardener/external-dns-management/pkg/apis/dns
github.com/gardener/external-dns-management/pkg/apis/dns/v1alpha1
github.com/gardener/external-dns-management/pkg/dns
# github.com/go-acme/lego/v4 v4.14.0
# github.com/go-acme/lego/v4 v4.14.0 => github.com/MartinWeindel/lego/v4 v4.4.1-0.20231116095906-a41bce273050
## explicit; go 1.20
github.com/go-acme/lego/v4/acme
github.com/go-acme/lego/v4/acme/api
Expand Down Expand Up @@ -922,3 +922,4 @@ sigs.k8s.io/yaml
## explicit; go 1.15
software.sslmate.com/src/go-pkcs12
software.sslmate.com/src/go-pkcs12/internal/rc2
# github.com/go-acme/lego/v4 => github.com/MartinWeindel/lego/v4 v4.4.1-0.20231116095906-a41bce273050

0 comments on commit 771623f

Please sign in to comment.